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

内核版本:2.6.14

glibc版本:2.3.6

CPU平台:arm

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

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

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

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

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

自己动手实现arm函数栈帧回溯【转】的更多相关文章

  1. c函数调用过程原理及函数栈帧分析

    转载自地址:http://blog.csdn.net/zsy2020314/article/details/9429707       今天突然想分析一下函数在相互调用过程中栈帧的变化,还是想尽量以比 ...

  2. Cortex-M3双堆栈MSP和PSP+函数栈帧

    为了防止几百年以后找不到该文章,特此转载 ------------------------------------------------开始转载--------------------------- ...

  3. C函数调用过程原理及函数栈帧分析(转)

    在x86的计算机系统中,内存空间中的栈主要用于保存函数的参数,返回值,返回地址,本地变量等.一切的函数调用都要将不同的数据.地址压入或者弹出栈.因此,为了更好地理解函数的调用,我们需要先来看看栈是怎么 ...

  4. 谈谈arm下的函数栈

    引言 这篇文章简要说说函数是怎么传入参数的,我们都知道,当一个函数调用使用少量参数(ARM上是少于等于4个)时,参数是通过寄存器进行传值(ARM上是通过r0,r1,r2,r3),而当参数多于4个时,会 ...

  5. [Android Pro] 深入理解函数的调用过程——栈帧

    cp :http://blog.csdn.net/x_perseverance/article/details/78897637 每一个函数被调用时,都会为函数开辟一块空间,这块空间就称为栈帧. 首先 ...

  6. Linux内核调试方法总结之栈帧

    栈帧 栈帧和指针可以说是C语言的精髓.栈帧是一种特殊的数据结构,在C语言函数调用时,栈帧用来保存当前函数的父一级函数的栈底指针,当前函数的局部变量以及被调用函数返回后下一条汇编指令的地址.如下图所示: ...

  7. C语言的函数调用过程(栈帧的创建与销毁)

    从汇编的角度解析函数调用过程 看看下面这个简单函数的调用过程: int Add(int x,int y) { ; sum = x + y; return sum; } int main () { ; ...

  8. Windows x64 栈帧结构

    0x01 前言 Windows 64位下函数调用约定变为了快速调用约定,前4个参数采用rcx.rdx.r8.r9传递,多余的参数从右向左依次使用堆栈传递.本次文章是对于Windows 64位下函数调用 ...

  9. dwarf是如何处理栈帧的?

    dwarf是如何处理栈帧的? DW_AT_frame_base 表明函数栈帧的起始点 95 < 1><0x000000ca>    DW_TAG_subprogram 96   ...

随机推荐

  1. change object keys & UpperCase & LowerCase

    change object keys & UpperCase & LowerCase .toLocaleUpperCase(); && .toLocaleLowerCa ...

  2. InnoDB,select为啥会阻塞insert?

    MySQL的InnoDB的细粒度行锁,是它最吸引人的特性之一. 但是,如<InnoDB,5项最佳实践>所述,如果查询没有命中索引,也将退化为表锁. InnoDB的细粒度锁,是实现在索引记录 ...

  3. .Net MVC 实现长轮询

    什么是长轮询? 长轮询是“服务器推”技术实现方式的一种,可以将服务端发生的变化实时传送到客户端而无须客户端频繁的地刷新.发送请求. 长轮询原理? 客户端向服务器发送Ajax请求,服务器接收到请求后,保 ...

  4. 生成模型(Generative Model)Vs 判别模型(Discriminative Model)

      概率图分为有向图(bayesian network)与无向图(markov random filed).在概率图上可以建立生成模型或判别模型.有向图多为生成模型,无向图多为判别模型. 判别模型(D ...

  5. 用Docker搭建Nexus私服

    搜索Nexus 在docker容器中加载Nexus镜像 发布本地项目到Nexus私服 配置连接方式 发布指令 打源码包上传插件 搜索Nexus   在我们打算使用Nexus时,我们先搜索一下docke ...

  6. POJ3421:X-factor Chains——题解

    http://poj.org/problem?id=3421 题目大意:一个数列,起始为1,终止为一给定数X,满足Xi < Xi+1 并且Xi | Xi+1. 求出数列最大长度和该长度下的情况数 ...

  7. BZOJ5323 & 洛谷4562:[JXOI2018]游戏——题解

    https://www.luogu.org/problemnew/show/P4562 https://www.lydsy.com/JudgeOnline/problem.php?id=5323 (B ...

  8. X day1

    题目pdf 官方题解 T1: 我们可以发现此题若要求$[L,R]$区间的答案,其实就是再求前缀和,我们设$b$为当前出现次数最多的字符,$c$为最小,所以答案为$s[b]_r-s[c]_r-(s[b] ...

  9. 【二分】【P1314】 【NOIP2011D2T2】聪明的质监员

    传送门 Description 小T 是一名质量监督员,最近负责检验一批矿产的质量.这批矿产共有 \(n\) 个矿石,从 \(1\) 到 \(n\) 逐一编号,每个矿石都有自己的重量 \(w_i\) ...

  10. js ajax向后台传数组可以直接拼接传输

    ajax向后台传数组是可以直接传的,写法如下 var ids = [ ]; $(dom1).each(function(){ ids.push($(this).val()); }); var  use ...