• 自己动手实现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函数代替。

  • 相关阅读:
    VC++使用socket进行TCP、UDP通信实例总结
    [Android Pro] 调用系统相机和图库,裁剪图片
    [Android Pro] 查看 keystore文件的签名信息 和 检查apk文件中的签名信息
    [Android 新特性] 谷歌发布Android Studio开发工具1.0正式版(组图) 2014-12-09 09:35:40
    [Android 新特性] 有史来最大改变 Android 5.0十大新特性
    [Android Pro] service中显示一个dialog 或者通过windowmanage显示view
    [Android Pro] 通过Android trace文件分析死锁ANR
    [Android Memory] Android 的 StrictMode
    [Android Memory] Android性能测试小工具Emmagee
    [Android Memory] Android内存管理、监测剖析
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/7678651.html
Copyright © 2020-2023  润新知