zoukankan      html  css  js  c++  java
  • 自己动手实现arm函数栈帧回溯【转】

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

    内核版本:2.6.14

    glibc版本:2.3.6

    CPU平台:arm

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

    [plain] view plaincopy在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 "   
    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) ", 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] != '')  
    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] != '')  
    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 ", a);  
    136.     B(2);  
    137. }  
    138.   
    139. void B(int b)  
    140. {  
    141.     printf("%d: B call C ", 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 ", 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 "   
    158.         : "=r"(ip)  
    159.     );  
    160.     printf("sp = 0x%x ", ip);  
    161.     struct sigframe_ce123 * sigframe = (struct sigframe_ce123 * )ip;*/  
    162.   
    163.     if(NULL != ptr)  
    164.     {  
    165.         printf(" unhandled page fault (%d) at: 0x%08x ", 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 ", 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 ", i+1, strings[i]);  
    184.         free(strings);  
    185.     }  
    186.     else  
    187.         printf("error! ");  
    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函数代替。

  • 相关阅读:
    Java实现 蓝桥杯 历届试题 连号区间数
    Java实现 蓝桥杯 历届试题 连号区间数
    Java实现 蓝桥杯 历届试题 连号区间数
    Java实现 蓝桥杯 历届试题 连号区间数
    Java实现 蓝桥杯 历届试题 连号区间数
    Java实现 蓝桥杯 历届试题 大臣的旅费
    Java实现 蓝桥杯 历届试题 大臣的旅费
    Java实现 蓝桥杯 历届试题 大臣的旅费
    Java实现 蓝桥杯 历届试题 大臣的旅费
    Navicat查询哪些表有指定字段名
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/7678651.html
Copyright © 2011-2022 走看看