自己动手实现arm函数栈帧回溯【转】

简介:

转自:http://blog.csdn.net/dragon101788/article/details/18668505

内核版本:2.6.14

glibc版本:2.3.6

CPU平台:arm

glic中其实有这些函数,当时用的uclib版本较低,没有这些函数,但又需要,只能自己实现了(较高的版本应该有这些函数,换版本很麻烦),而且可以加深自己对这方面的理解.原理性的东西就不深入讲解了,直接上例子!

 

[plain]  view plain copy 在CODE上查看代码片 派生到我的代码片
 
 
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <signal.h>  
  4. #include <assert.h>  
  5. #include <ucontext.h>  
  6.   
  7. void A(int a);  
  8. void B(int b);  
  9. void C(int c);  
  10. void DebugBacktrace(unsigned int sn , siginfo_t  *si , void *ptr);  
  11.   
  12. typedef struct  
  13. {  
  14.     const char *dli_fname;  /* File name of defining object.  */  
  15.     void *dli_fbase;        /* Load address of that object.  */  
  16.     const char *dli_sname;  /* Name of nearest symbol.比如函数名*/  
  17.     void *dli_saddr;        /* Exact value of nearest symbol.比如函数的起始地址*/  
  18. } Dl_info;  
  19.   
  20. struct ucontext_ce123 {  
  21.     unsigned long     uc_flags;  
  22.     struct ucontext  *uc_link;  
  23.     stack_t       uc_stack;  
  24.     struct sigcontext uc_mcontext;  
  25.     sigset_t      uc_sigmask;   /* mask last for extensibility */  
  26. }ucontext_ce123_;  
  27.   
  28. struct sigframe_ce123 {    
  29.     struct sigcontext sc;//保存一组寄存器上下文    
  30.     unsigned long extramask[1];    
  31.     unsigned long retcode;//保存返回地址    
  32.     //struct aux_sigframe aux __attribute__((aligned(8)));    
  33. }sigframe_ce123;   
  34.   
  35. int backtrace_ce123 (void **array, int size);  
  36. char ** backtrace_symbols_ce123 (void *const *array, int size);  
  37.   
  38.   
  39. int backtrace_ce123 (void **array, int size)  
  40. {  
  41.     if (size <= 0)  
  42.         return 0;  
  43.   
  44.     int *fp = 0, *next_fp = 0;  
  45.     int cnt = 0;  
  46.     int ret = 0;  
  47.   
  48.     __asm__(  
  49.         "mov %0, fp\n"   
  50.         : "=r"(fp)  
  51.     );  
  52.   
  53.   
  54.     array[cnt++] = (void *)(*(fp-1));  
  55.   
  56.     next_fp = (int *)(*(fp-3));  
  57.     while((cnt <= size) && (next_fp != 0))  
  58.     {  
  59.         array[cnt++] = (void *)*(next_fp - 1);  
  60.         next_fp = (int *)(*(next_fp-3));  
  61.     }  
  62.   
  63.   
  64.     ret = ((cnt <= size)?cnt:size);  
  65.     printf("Backstrace (%d deep)\n", ret);  
  66.   
  67.     return ret;  
  68. }  
  69.   
  70. char ** backtrace_symbols_ce123 (void *const *array, int size)  
  71. {  
  72. # define WORD_WIDTH 8  
  73.     Dl_info info[size];  
  74.     int status[size];  
  75.     int cnt;  
  76.     size_t total = 0;  
  77.     char **result;  
  78.   
  79.     /* Fill in the information we can get from `dladdr'.  */  
  80.     for (cnt = 0; cnt < size; ++cnt)  
  81.     {  
  82.         status[cnt] = _dl_addr (array[cnt], &info[cnt]);  
  83.         if (status[cnt] && info[cnt].dli_fname && info[cnt].dli_fname[0] != '\0')  
  84.         /* We have some info, compute the length of the string which will be  
  85.         "<file-name>(<sym-name>) [+offset].  */  
  86.         total += (strlen (info[cnt].dli_fname ?: "")  
  87.             + (info[cnt].dli_sname ? strlen (info[cnt].dli_sname) + 3 + WORD_WIDTH + 3 : 1)  
  88.             + WORD_WIDTH + 5);  
  89.         else  
  90.             total += 5 + WORD_WIDTH;  
  91.     }  
  92.   
  93.   
  94.     /* Allocate memory for the result.  */  
  95.     result = (char **) malloc (size * sizeof (char *) + total);  
  96.     if (result != NULL)  
  97.     {  
  98.         char *last = (char *) (result + size);  
  99.   
  100.         for (cnt = 0; cnt < size; ++cnt)  
  101.         {  
  102.             result[cnt] = last;  
  103.   
  104.             if (status[cnt] && info[cnt].dli_fname && info[cnt].dli_fname[0] != '\0')  
  105.             {  
  106.                 char buf[20];  
  107.   
  108.                 if (array[cnt] >= (void *) info[cnt].dli_saddr)  
  109.                     sprintf (buf, "+%#lx", \  
  110.                         (unsigned long)(array[cnt] - info[cnt].dli_saddr));  
  111.                 else  
  112.                     sprintf (buf, "-%#lx", \  
  113.                         (unsigned long)(info[cnt].dli_saddr - array[cnt]));  
  114.   
  115.                 last += 1 + sprintf (last, "%s%s%s%s%s[%p]",  
  116.                     info[cnt].dli_fname ?: "",  
  117.                     info[cnt].dli_sname ? "(" : "",  
  118.                     info[cnt].dli_sname ?: "",  
  119.                     info[cnt].dli_sname ? buf : "",  
  120.                     info[cnt].dli_sname ? ") " : " ",  
  121.                     array[cnt]);  
  122.             }  
  123.             else  
  124.                 last += 1 + sprintf (last, "[%p]", array[cnt]);  
  125.         }  
  126.         assert (last <= (char *) result + size * sizeof (char *) + total);  
  127.     }  
  128.   
  129.     return result;  
  130. }  
  131.   
  132.   
  133. void A(int a)  
  134. {  
  135.     printf("%d: A call B\n", a);  
  136.     B(2);  
  137. }  
  138.   
  139. void B(int b)  
  140. {  
  141.     printf("%d: B call C\n", b);  
  142.     C(3);       /* 这个函数调用将导致段错误*/  
  143. }  
  144.   
  145. void C(int c)  
  146. {  
  147.     char *p = (char *)c;  
  148.     *p = 'A';   /* 如果参数c不是一个可用的地址值,则这条语句导致段错误 */  
  149.     printf("%d: function C\n", c);  
  150. }  
  151.   
  152. /* SIGSEGV信号的处理函数,回溯栈,打印函数的调用关系*/  
  153. void DebugBacktrace(unsigned int sn , siginfo_t  *si , void *ptr)  
  154. {  
  155.     /*int *ip = 0;  
  156.     __asm__(  
  157.         "mov %0, ip\n"   
  158.         : "=r"(ip)  
  159.     );  
  160.     printf("sp = 0x%x\n", ip);  
  161.     struct sigframe_ce123 * sigframe = (struct sigframe_ce123 * )ip;*/  
  162.   
  163.     if(NULL != ptr)  
  164.     {  
  165.         printf("\n\nunhandled page fault (%d) at: 0x%08x\n", si->si_signo,si->si_addr);  
  166.   
  167.         struct ucontext_ce123 *ucontext = (struct ucontext_ce123 *)ptr;  
  168.         int pc = ucontext->uc_mcontext.arm_pc;         
  169.   
  170.         void *pc_array[1];   
  171.         pc_array[0] = pc;  
  172.         char **pc_name = backtrace_symbols_ce123(pc_array, 1);  
  173.         printf("%d: %s\n", 0, *pc_name);  
  174.   
  175. #define SIZE 100  
  176.         void *array[SIZE];  
  177.         int size, i;  
  178.         char **strings;  
  179.         size = backtrace_ce123(array, SIZE);  
  180.         strings = backtrace_symbols_ce123(array, size);   
  181.   
  182.         for(i=0;i<size;i++)  
  183.             printf("%d: %s\n", i+1, strings[i]);  
  184.         free(strings);  
  185.     }  
  186.     else  
  187.         printf("error!\n");  
  188.     exit(-1);  
  189. }  
  190.   
  191. int main(int argc, char **argv)  
  192. {     
  193.     char a;  
  194.   
  195.     struct sigaction s;  
  196.     s.sa_flags = SA_SIGINFO;  
  197.     s.sa_sigaction = (void *)DebugBacktrace;  
  198.   
  199.     sigaction (SIGSEGV,&s,NULL);  
  200.   
  201.     A(1);  
  202.     C(&a);      
  203.   
  204.     return 0;  
  205.   
  206. }  

代码的下载地址:http://download.csdn.net/detail/ce123/5063160

编译命令:arm-linux-gcc -rdynamic -o segfault segfault.c

_dl_addr链接不通过时,使用-ldl。如果没有该函数,可用dladdr函数代替。








本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/7678651.html,如需转载请自行联系原作者

相关文章
【各种问题处理】X86架构和ARM架构的区别
【1月更文挑战第13天】【各种问题处理】X86架构和ARM架构的区别
|
4月前
|
Web App开发 NoSQL 安全
ARM架构-银河麒麟v10-server离线安装Harbor
ARM架构-银河麒麟v10-server离线安装Harbor
294 0
|
4月前
|
边缘计算 编译器 数据中心
X86架构与Arm架构的主要区别分析
X86架构与Arm架构的主要区别分析
463 0
|
3月前
|
缓存 API Android开发
一起学点ARM的微架构二?
一起学点ARM的微架构二?
71 1
|
6月前
|
存储 缓存 监控
安谋科技(Arm China)马闯:Arm架构下性能分析与优化介绍
2023年9月19日,系列课程第九节《Arm®架构下性能分析与优化介绍》正式上线,由安谋科技 (Arm China)主任工程师马闯主讲,内容涵盖:Arm架构下性能监控单元 (PMU) 介绍、Arm统计性能分析扩展 (SPE) 介绍、Arm性能分析工具介绍、Arm架构下性能优化案例分享,本期节目在阿里云官网、阿里云微信视频号、阿里云钉钉视频号、InfoQ官网、阿里云开发者微信视频号、阿里云创新中心直播平台 & 微信视频号同步播出,同时可以点击【https://developer.aliyun.com/topic/ecs-yitian】进入【倚天实例迁移课程官网】了解更多内容。
|
6月前
|
Java Nacos Maven
Nacos一个arm架构的jdk8。
Nacos一个arm架构的jdk8。
176 1
|
1月前
|
存储 机器学习/深度学习 并行计算
阿里云服务器X86计算、Arm计算、GPU/FPGA/ASIC、高性能计算架构区别
在我们选购阿里云服务器的时候,云服务器架构有X86计算、ARM计算、GPU/FPGA/ASIC、弹性裸金属服务器、高性能计算可选,有的用户并不清楚他们之间有何区别,本文主要简单介绍下不同类型的云服务器有何不同,主要特点及适用场景有哪些。
阿里云服务器X86计算、Arm计算、GPU/FPGA/ASIC、高性能计算架构区别
|
1月前
|
存储 缓存 安全
【ARM架构】ARMv8-A 系统中的安全架构概述
【ARM架构】ARMv8-A 系统中的安全架构概述
31 0
|
1月前
|
存储 机器学习/深度学习 人工智能
嵌入式中一文搞懂ARM处理器架构
嵌入式中一文搞懂ARM处理器架构
37 1
|
1月前
|
弹性计算 Java 关系型数据库
ARM架构和避坑指南|开发者分享会
今天分享的内容来自阿里云倚天ECS高级架构师张先国的“ARM架构和避坑指南”。本文内容主要从ARM架构、C和Java如何避坑 、等方面详细讲解。