免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2666 | 回复: 8
打印 上一主题 下一主题

[Linux] 打印调用栈的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-09-06 17:20 |只看该作者 |倒序浏览
本帖最后由 kaka1902 于 2013-09-06 17:21 编辑

最近遇到一个难题:
在代码crash的时候,我有一段代码会捕获信号后打印调用栈:
调用栈是采用__build_frame_address()来获取当前调用地址的
{
int          n;
  unsigned int fpadd, fpaddnext;
  unsigned int stackadd = (unsigned int)&fpadd;

  fpadd = (unsigned int)__builtin_frame_address(1);

  for ( n = 0; n < nb; n++ )
    {
   
    tab[n]    = (void *)*(((unsigned int *)fpadd) + 1);
    fpaddnext = *(unsigned int *)fpadd;

    if ( (fpaddnext <= fpadd) || (fpaddnext > (stackadd + 0x10000)))
      {
      return (n + 1); // Next fp is outside the stack or too far
      }
    fpadd = fpaddnext;
    }
}

但是我测试了一下发现每次只能打一级调用的函数,再往下就没有了

这个问题可能跟什么相关?麻烦各位指点一下!

论坛徽章:
0
2 [报告]
发表于 2013-09-06 17:22 |只看该作者
补充一下
编译环境是ARM的交叉编译工具链?
有没有可能是工具链带的libc库编译选项指定的不对?

论坛徽章:
36
CU大牛徽章
日期:2013-09-18 15:24:20NBA常规赛纪念章
日期:2015-05-04 22:32:03牛市纪念徽章
日期:2015-07-24 12:48:5515-16赛季CBA联赛之辽宁
日期:2016-03-30 09:26:4715-16赛季CBA联赛之北控
日期:2016-03-30 11:26:2315-16赛季CBA联赛之广夏
日期:2016-05-20 15:46:5715-16赛季CBA联赛之吉林
日期:2016-05-24 11:38:0615-16赛季CBA联赛之青岛
日期:2016-05-30 13:41:3215-16赛季CBA联赛之同曦
日期:2016-06-23 16:41:052015年亚洲杯之巴林
日期:2015-02-03 15:05:04CU大牛徽章
日期:2013-09-18 15:24:52CU十二周年纪念徽章
日期:2013-10-24 15:46:53
3 [报告]
发表于 2013-09-06 23:48 |只看该作者
不懂也,不知道lZ的环境里有没有backtrace可以用

论坛徽章:
0
4 [报告]
发表于 2013-09-07 11:33 |只看该作者
试过backtrace(), 也是打不出来东西
感觉libc的栈都无法打印,难不成真是工具链提供libc编译的时候没有添加-rdynamic -ldl?

论坛徽章:
4
白羊座
日期:2013-09-17 21:59:30技术图书徽章
日期:2013-10-12 22:16:03白羊座
日期:2013-10-14 11:01:40双子座
日期:2013-12-17 18:26:39
5 [报告]
发表于 2013-09-07 12:03 |只看该作者
本帖最后由 井蛙夏虫 于 2013-09-07 12:03 编辑

回复 4# wps103
posix标准保证能在信号处理函数中安全调用的函数没有__builtin_frame_address和backtrace,所以这些是未定义行为。(man 7 signal)

论坛徽章:
0
6 [报告]
发表于 2013-09-08 10:43 |只看该作者
不在信号处理函数里面实现
做了一个实验,在宿主机上和ARM上分别测试一下代码:
宿主机:ubuntu
  1. #include <execinfo.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. void fun1(void);
  5. void fun2(void);
  6. void fun3(void);
  7. void print_stacktrace(void);


  8. int main(void)
  9. {
  10.     fun3();
  11.     return 0;
  12. }
  13. void fun1()
  14. {
  15.     fprintf(stderr,"stackstrace begin:\n");
  16.     print_stacktrace();
  17. }
  18. void fun2()
  19. {
  20.     fun1();
  21. }
  22. void fun3()
  23. {
  24.     fun2();
  25. }
  26. void print_stacktrace()
  27. {
  28.     int size = 16;
  29.     void * array[16];
  30.     int i=0;
  31.     int stack_num = backtrace(array, size);
  32.     char ** stacktrace = backtrace_symbols(array, stack_num);
  33.     for (i = 0; i < stack_num; ++i)
  34.     {
  35.         fprintf(stderr,"%s\n", stacktrace[i]);
  36.     }
  37.     free(stacktrace);
  38. }
复制代码
编译:
宿主机:
gcc backtrace.c -rdynamic -g -o backtrace
交叉编译:
arm-linux-cc backtrace.c -rdynamic -g -o backtrace

运行结果:
宿主机:
stackstrace begin:
./backtrace(print_stacktrace+0x26) [0x80487ab]
./backtrace(fun1+0x33) [0x8048769]
./backtrace(fun2+0xb) [0x8048776]
./backtrace(fun3+0xb) [0x8048783]
./backtrace(main+0xb) [0x804872f]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x83d113]
./backtrace() [0x8048691]


ARM:
stackstrace begin:
/lib/ld-linux.so.3 [0x40096000]

看起来跟安全性没什么关系,可能还是编译选项的问题?
大牛们请再指教!

论坛徽章:
17
处女座
日期:2013-08-27 09:59:352015亚冠之柏太阳神
日期:2015-07-30 10:16:402015亚冠之萨济拖拉机
日期:2015-07-29 18:58:182015年亚洲杯之巴勒斯坦
日期:2015-03-06 17:38:17摩羯座
日期:2014-12-11 21:31:34戌狗
日期:2014-07-20 20:57:32子鼠
日期:2014-05-15 16:25:21亥猪
日期:2014-02-11 17:32:05丑牛
日期:2014-01-20 15:45:51丑牛
日期:2013-10-22 11:12:56双子座
日期:2013-10-18 16:28:17白羊座
日期:2013-10-18 10:50:45
7 [报告]
发表于 2013-09-09 15:30 |只看该作者
回复 1# kaka1902


    和你传的参数1有关吧。只处理一层的frame stack。__builtin_frame_address(1)。改大点试试

论坛徽章:
0
8 [报告]
发表于 2013-09-10 14:16 |只看该作者
回复 7# myworkstation

This function is similar to __builtin_return_address, but it returns the address of the function frame rather than the return address of the function. Calling __builtin_frame_address with a value of 0 yields the frame address of the current function, a value of 1 yields the frame address of the caller of the current function, and so forth.

The frame is the area on the stack which holds local variables and saved registers. The frame address is normally the address of the first word pushed on to the stack by the function. However, the exact definition depends upon the processor and the calling convention. On the Motorola 68000, if the function has a frame, then __builtin_frame_address will return the value of the frame pointer register a6 if level is 0.

This function should be used with a nonzero argument only for debugging purposes.

从解释来看,入参并不是指定需要获取多少个stack frame,而是指定获取第几级的调用stack frame
因此改大应该也没有什么好处,不过我可以试下认为多取几级堆栈,看看究竟有没有东西


   

论坛徽章:
4
白羊座
日期:2013-09-17 21:59:30技术图书徽章
日期:2013-10-12 22:16:03白羊座
日期:2013-10-14 11:01:40双子座
日期:2013-12-17 18:26:39
9 [报告]
发表于 2013-09-10 18:41 |只看该作者
回复 8# wps103
x86平台能打印,你改改试试
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <dlfcn.h>
  4. #include <execinfo.h>

  5. #define BACKTRACE_MAXDEPTH 32

  6. struct layout               // 来自glibc-2.16.0/sysdeps/generic
  7. {
  8.       void *__unbounded next;
  9.       void *__unbounded return_address;
  10. };

  11. int my_backtrace(void **arr, int maxsize)
  12. {
  13.     int cnt = 0;
  14.     void *fp = __builtin_frame_address(0);
  15.     struct layout *lp = (struct layout *)fp;
  16.     while (cnt < maxsize)
  17.     {

  18.         arr[cnt++] = lp->return_address;
  19.         if (!lp->next)
  20.         {
  21.             break;
  22.         }
  23.         lp = (struct layout*)lp->next;
  24.     }
  25.     return cnt;
  26. }


  27. void my_backtrace_symbols(void* const* arr, int size)
  28. {
  29.     for (int i = 1; i < size; ++i)
  30.     {
  31.         Dl_info info;
  32.         if (dladdr(arr[i], &info))
  33.             fprintf(stderr, "%s(%s+0x%x) [%p]\n", info.dli_fname, info.dli_sname, (int)arr[i] - (int)info.dli_saddr, arr[i]);
  34.         else
  35.             fprintf(stderr, "[%p]\n", arr[i]);
  36.     }
  37. }

  38. void print_my_stacktrace()
  39. {
  40.     void * array[BACKTRACE_MAXDEPTH];
  41.     int i=0;
  42.     int stack_num = my_backtrace(array, BACKTRACE_MAXDEPTH);
  43.     char ** stacktrace = backtrace_symbols(array, stack_num);
  44.     for (i = 0; i < stack_num; ++i)
  45.     {
  46.         fprintf(stderr,"%s\n", stacktrace[i]);
  47.     }
  48.     free(stacktrace);
  49. }

  50. void fun1()
  51. {
  52.     fprintf(stderr,"stackstrace begin:\n");
  53.     print_my_stacktrace();
  54. }

  55. void fun2()
  56. {
  57.     fun1();
  58. }

  59. void fun3()
  60. {
  61.     fun2();
  62. }

  63. int main(void)
  64. {
  65.     fun3();
  66.     return 0;
  67. }
复制代码
编译指令
  1. gcc print_backtrace.c -ldl -rdynamic -D_GNU_SOURCE -std=gnu99 -Wall
复制代码
结果
  1. stackstrace begin:
  2. ./a.out(print_my_stacktrace+0x26) [0x80488a5]
  3. ./a.out(fun1+0x33) [0x804893a]
  4. ./a.out(fun2+0xb) [0x8048947]
  5. ./a.out(fun3+0xb) [0x8048954]
  6. ./a.out(main+0xb) [0x8048961]
  7. /lib/libc.so.6(__libc_start_main+0xf3) [0x4a0066b3]
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP