一.用途:
主要用于程序异常退出时寻找错误原因
二.功能:
回溯堆栈,简单的说就是可以列出当前函数调用关系
三.原理:
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_DEBUGstatic void print_reason(int sig, siginfo_t * info, void *secret){void *array[10];size_t size;#ifdef PRINT_DEBUGchar **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[i]);free(strings);#elseint fd = open("err.log", O_CREAT | O_WRONLY);size = backtrace(array, 10);backtrace_symbols_fd(array, size, fd);close(fd);#endifexit(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

2. 根据不同的处理器自已实现backtrace
i. arm的backtrace函数实现

static int backtrace_xy(void **BUFFER, int SIZE){volatile int n = 0;volatile int *p;volatile int *q;volatile int ebp1;volatile int eip1;volatile int i = 0;p = &n;ebp1 = p[4];eip1 = p[6];fprintf(stderr, "======================= backtrace_xy addr: 0x%0x, param1: 0x%0x, param2: 0x%0x\n",backtrace_xy, &BUFFER, &SIZE);fprintf(stderr, "n addr is 0x%0x\n", &n);fprintf(stderr, "p addr is 0x%0x\n", &p);for (i = 0; i &lt; SIZE; i++){fprintf(stderr, "ebp1 is 0x%0x, eip1 is 0x%0x\n", ebp1, eip1);BUFFER[i] = (void *)eip1;p = (int*)ebp1;q = p - 5;eip1 = q[5];ebp1 = q[2];if (ebp1 == 0 || eip1 == 0)break;}fprintf(stderr, "total level: %d\n", i);return i;}

六.举例2:

/*main.c*/#include "sigsegv.h"#include &lt;string.h>int die() {char *err = NULL;  strcpy(err, "gonner");return 0;}int main() {return die();}/*sigsegv.c*/#define _GNU_SOURCE#include <memory.h>#include <stdlib.h>#include <stdio.h>#include <signal.h>#include <ucontext.h>#include <dlfcn.h>#include <execinfo.h>#define NO_CPP_DEMANGLE#ifndef NO_CPP_DEMANGLE#include <cxxabi.h>#endif#if defined(REG_RIP)# define SIGSEGV_STACK_IA64# define REGFORMAT "%016lx"#elif defined(REG_EIP)# define SIGSEGV_STACK_X86# define REGFORMAT "%08x"#else# define SIGSEGV_STACK_GENERIC# define REGFORMAT "%x"#endifstatic void signal_segv(int signum, siginfo_t* info, void*ptr) {static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};    size_t i;    ucontext_t *ucontext = (ucontext_t*)ptr;#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)int f = 0;    Dl_info dlinfo;void **bp = 0;void *ip = 0;#elsevoid *bt[20];char **strings;    size_t sz;#endif    fprintf(stderr, "Segmentation Fault!\n");    fprintf(stderr, "info-&gt;si_signo = %d\n", signum);    fprintf(stderr, "info-&gt;si_errno = %d\n", info-&gt;si_errno);//    fprintf(stderr, "info-&gt;si_code  = %d (%s)\n", info-&gt;si_code, info-&gt;si_codes[si_code]);    fprintf(stderr, "info-&gt;si_addr  = %p\n", info-&gt;si_addr);for(i = 0; i < NGREG; i++)        fprintf(stderr, "reg[%02d]       = 0x" REGFORMAT "\n", i, ucontext->uc_mcontext.gregs[i]);#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)# if defined(SIGSEGV_STACK_IA64)    ip = (void*)ucontext-&gt;uc_mcontext.gregs[REG_RIP];    bp = (void**)ucontext-&gt;uc_mcontext.gregs[REG_RBP];# elif defined(SIGSEGV_STACK_X86)    ip = (void*)ucontext-&gt;uc_mcontext.gregs[REG_EIP];    bp = (void**)ucontext-&gt;uc_mcontext.gregs[REG_EBP];# endif    fprintf(stderr, "Stack trace:\n");while(bp != & ip) {if(!dladdr(ip, &dlinfo))break;const char *symname = dlinfo.dli_sname;#ifndef NO_CPP_DEMANGLEint status;char *tmp = __cxa_demangle(symname, NULL, 0, &status);if(status == 0 !=& tmp)            symname = tmp;#endif        fprintf(stderr, "% 2d: %p < %s+%u> (%s)\n",                ++f,                ip,                symname,                (unsigned)(ip - dlinfo.dli_saddr),                dlinfo.dli_fname);#ifndef NO_CPP_DEMANGLEif(tmp)            free(tmp);#endifif(dlinfo.dli_sname != !strcmp(dlinfo.dli_sname, "main"))break;        ip = bp[1];        bp = (void**)bp[0];    }#else    fprintf(stderr, "Stack trace (non-dedicated):\n");    sz = backtrace(bt, 20);    strings = backtrace_symbols(bt, sz);for(i = 0; i < sz; ++i)        fprintf(stderr, "%s\n", strings[i]);#endif    fprintf(stderr, "End of stack trace\n");    exit (-1);}int setup_sigsegv() {struct sigaction action;    memset(&action, 0, sizeof(action));    action.sa_sigaction = signal_segv;    action.sa_flags = SA_SIGINFO;if(sigaction(SIGSEGV, &action, NULL) &lt; 0) {        perror("sigaction");return 0;    }return 1;}#ifndef SIGSEGV_NO_AUTO_INITstatic void __attribute((constructor)) init(void){    setup_sigsegv();}#endif/*sigsegv.h*/#ifndef __sigsegv_h__#define __sigsegv_h__#ifdef __cplusplusextern "C" {#endifint setup_sigsegv();#ifdef __cplusplus}#endif#endif /* __sigsegv_h__ */编译时需要加入-rdynamic -ldl –ggdb

voidhandle_signal_error(int rec_signal,siginfo_t* signal_info,void* context){NE_Info* __attribute__ ((unused)) ne_info = NULL;struct sigaction action;FILE* file;void* backtr[NUMBER_OF_BACKTRACE];cpal_uns32 __attribute__ ((unused)) i = 0;cpal_uns32 backtr_size = 0;ucontext_t *u_context;time_t seconds_time;struct tm* time_struct;cpal_si32 ret_t;char filename[SIZE_OF_FILENAME];  if(g_handler_running)return;g_handler_running = CPAL_TRUE;ret_t = time(&seconds_time); if(ret_t != - 1){time_struct = gmtime(&seconds_time);snprintf(filename,SIZE_OF_FILENAME,"%s%d%d%d-%d%d%d-%s",BACKTRACE_FILE_PATH,time_struct->tm_mon,time_struct-&gt;tm_mday,(time_struct-&gt;tm_year-100)+2000,time_struct-&gt;tm_hour,time_struct-&gt;tm_min,time_struct-&gt;tm_sec,BACKTRACE_FILE);}else{snprintf(filename,SIZE_OF_FILENAME,"%s",BACKTRACE_FILE);}file = fopen(filename,"w");

if(file == NULL){return;}if(signal_info == NULL){return;}if(context == NULL){return;}u_context = (ucontext_t*)context;/*Restore the default action for this signal and re-raise it, so that the default action occurs. */action.sa_sigaction = SIG_DFL;sigemptyset(&action.sa_mask);action.sa_flags = SA_RESTART;sigaction(rec_signal,&action,NULL);/* Print out the backtrace. */backtr_size = backtrace(backtr,20);

/* The backtrace points to sigaction in libc, not to where the signal was actually raised.   This overwrites the sigaction with where the signal was sent, so we can resolve the sender. */#if __WORDSIZE == 64backtr[1] = (void*)u_context-&gt;uc_mcontext.gregs[REG_RIP];#elsebacktr[1] = (void*)u_context-&gt;uc_mcontext.gregs[REG_EIP];#endif //__WORDSIZE

    backtrace_symbols_fd(backtr,backtr_size,fileno(file));fprintf(file,"Backtrace is above.\nFatal signal %d received.\n",rec_signal);#if __WORDSIZE == 64    fprintf(file,"Signal received at address %p from 0x%08x.\n",signal_info-&gt;si_addr,                                                          u_context-&gt;uc_mcontext.gregs[REG_RIP]);#else        fprintf(file,"Signal received at address %p from 0x%08x.\n",signal_info-&gt;si_addr,                                                          u_context-&gt;uc_mcontext.gregs[REG_EIP]);#endif //__WORDSIZE

#if CPAL_LM_DEBUG/* Print all NE_Infos */for(; i < MAX_NO_OF_CONNS; i++){ne_info = g_ne_hash_tab[i];while(ne_info != NULL){      ne_info = ne_info->next_ne;}}#endiffflush(file);fclose(file);sleep (50); /* Sleep for 50 seconds */g_handler_running = *_FALSE;raise(rec_signal);}

转载于:https://www.cnblogs.com/suyanghao/archive/2011/10/31/2230858.html

引:善用backtrace解决大问题相关推荐

  1. 对话李国杰:突破麦肯锡和图灵的框框,人工智能要解决大问题丨GAIR 2021

    承载东莞突破固有发展路径而生的松山湖,是我国城市经济高质量转型的一个生动缩影. 在东莞启动的"科技东莞"计划中,李国杰是最早参与合作的开拓者.如果细数中国IT界的商业大咖,他的名字 ...

  2. 随机字符串解决大问题之腾讯网如何实现手机扫描二维码登录qq功能的

    随机字符串解决大问题之腾讯网如何实现手机扫描二维码登录qq功能的 腾讯网(www.qq.com)有一个扫码登录功能很有意思, 点击首页一键登录按钮,就会展现一个二维码,用手机qq扫描此二维码就可以使当 ...

  3. 日志级别动态调整——小工具解决大问题

    随着外卖业务的快速发展,业务复杂度不断增加,线上系统环境有任何细小波动,对整个外卖业务都可能产生巨大的影响,甚至形成灾难性的雪崩效应,造成巨大的经济损失.每一次客诉.系统抖动等都是对技术人员的重大考验 ...

  4. 小窍门解决大问题(绝对值得收藏)

    这里搜集了好多生活的小窍门,希望能给大家带来更多的方便,让我们的生活越来越美好! 1.不用水,毛绒玩具巧清洁 方法:将半碗大粒盐(即粗盐,超市有售,2元一袋)和脏了的毛绒玩具一起放入一个塑料袋,系口, ...

  5. JDK8使用G1 垃圾回收器能解决大问题吗?

    本文想突出两个问题: 解决问题的思路:从最原始的角度去思考,问题的本身是因为缓存数据导致的GC,那我们就应该去思考缓存数据是否合理,而不是去思考JVM的参数是否合理 学习G1的知识,其关键的概念,关键 ...

  6. 小窍门解决大问题(组图)

    1.洗头时,在水中放少许盐,也可以预防脱发. 2.用醋洗头,可以令头发飘顺,容易打理而且兼有去头皮屑的功效.特别适合烫染后的头发. 3.刷牙时在牙膏上加上一点小苏打,刷三次后牙齿洁白如玉,牙锈自然脱落 ...

  7. Excel 只需要几秒钟就可以解决大问题的好技巧

    2019独角兽企业重金招聘Python工程师标准>>> ❶删除数据重复项 ​❷日期秒变星期 ❸批量数据增加计量单位 ❹快速核对两表数据差异 ❺快速取消合并单元格 ❻美观表格取消网格线 ...

  8. 开发淘宝模板:php小知识点,解决大问题

    开发淘宝SDK,并不需要多少复杂的php知识.这里总结了几点,不一定全面,反正够用就行. 1.explode(separator,string,limit)    功能:将字符串拆分成数组 当获取的f ...

  9. 超级实用--解决大问题了--如何设置哔哩哔哩-实现3,4倍速视频播放---工作技巧001

    这个太实用了,为什么....因为我平时看教程的时候,如果速度过慢,就会影响效率,因为很多的技术点 都已经知道是怎么回事,很熟悉了,想跳过吧,又想听听熟悉一下,而如果一直用2倍速播放,又浪费时间 但是播 ...

最新文章

  1. 百度Apollo发布中国首个自动驾驶安全报告,L3级别产品2020年量产上市
  2. python modbus类封装_Python 中引入一个文件,模块的概念
  3. .NET Core微服务之基于Ocelot实现API网关服务(续)
  4. pycharm 自动生成文件注释和函数注释
  5. html左侧td字体居右,如何在td中控制字体右对齐 且加粗_html/css_WEB-ITnose
  6. Ubuntu18.04.4 环境下对属性加密算法CP-ABE环境搭建
  7. 的向上取整函数_计算机二级Excel常用函数解析
  8. windows下搭建基于nginx的rtmp服务器
  9. 【LeetCode】剑指 Offer 26. 树的子结构
  10. elasticsearch type类型创建时注意项目,最新的elasticsearch已经不建议一个索引下多个type...
  11. JQuery判断元素是否存在
  12. 维基媒体宣布采用 Vue.js 进行前端开发
  13. ubuntu16.04安装mongodb
  14. bzoj 3012: [Usaco2012 Dec]First! Trie+拓扑排序
  15. mac mysql 移动硬盘_MAC上安装Fuse for macOS以支持读取NTFS格式的移动硬盘
  16. 关于新浪微博开放平台第三方登录接口问题
  17. Android Title标题栏的修改(隐藏,菜单)
  18. 对 Python 代码使用的词语标记化器 tokenize,你懂了吗?【Python|标准库|tokenize】
  19. oracle 查找所有序列,Oracle查询所有序列
  20. U盘文件变快捷方式--解决办法

热门文章

  1. Java监听器Listener入门示例
  2. Hibernate执行原理总结
  3. 【示例】Lucene查询索引库编程步骤
  4. gpib安装包 python_ioctl errorno:25在使用pythongpib的GPIB通信中
  5. centos7.5安装influxdb-1.7.8
  6. Qt Remote Object(QtRO)给指定的客户端发送消息
  7. QML 实现图片帧渐隐渐显轮播
  8. 卸载LINUX自带的JDK——linux-jdk-java
  9. oss多线程 上传_解读阿里云oss-android/ios-sdk 断点续传(多线程)
  10. 4.0 《数据库系统概论》数据库安全性详解---(存取控制、DACMAC、视图机制、审计Audit....)