分享

c中如何打印函数调用堆栈?

 quasiceo 2013-02-19
c中如何打印函数调用堆栈?
 如何在一个函数中打印出来调用它的上一级函数名称?
比如在做内存泄漏检测的时候,发现只打印分配内存点的信息还不够,因为有时候有多个流程同时调用一个地方分配内存,最好能是象gdb那样打印出函数调用的堆栈来更方便一些。
如果是c++还能想到用抛出异常来尝试一下,c里面有什么好方法么?
原帖由 feasword 于 2007-6-17 20:06 发表
如题
如何在一个函数中打印出来调用它的上一级函数名称?
比如在做内存泄漏检测的时候,发现只打印分配内存点的信息还不够,因为有时候有多个流程同时调用一个地方分配内存,最好能是象gdb那样打印出函数调用的 ...

何不直接参考 gdb 的源码?

原帖由 feasword 于 2007-6-17 20:06 发表
如题
如何在一个函数中打印出来调用它的上一级函数名称?
比如在做内存泄漏检测的时候,发现只打印分配内存点的信息还不够,因为有时候有多个流程同时调用一个地方分配内存,最好能是象gdb那样打印出函数调用的 ...
  1. func1(....)
  2. {
  3. .....
  4. #ifdef MYFEBUG
  5.      func2(....,__func__);
  6. #endif
  7. ....
  8. }
  9. #ifdef MYFEBUG
  10. func2(....,const char* funcname)
  11. #else
  12. func2(...)
  13. #endif
  14. {
  15. #ifdef MYFEBUG
  16.        printf("%s:%s\n",__func__,funcname);
  17. #endif
  18. ....
  19. }
可以参考strace,我好像还用过一个什么trace。。。。的

这问题C版ms讨论了很多次了,info gcc  
__builtin_return_address
__builtin_frame_address
还有一个相关的, info libc
glibc中,
backtrace
backtrace_symbols
试验了一下,好像只能打印出地址,但是有函数名更方便些
在11楼的提示下在网上找了篇文章,自己裁减了一下

  1. //funstack.c
  2. #define _GNU_SOURCE
  3. #include <memory.h>
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <signal.h>
  7. #include <ucontext.h>
  8. #include <dlfcn.h>
  9. #include <execinfo.h>

  10. #if defined(REG_RIP)
  11. # define SIGSEGV_STACK_IA64
  12. # define REGFORMAT "%016lx"
  13. #elif defined(REG_EIP)
  14. # define SIGSEGV_STACK_X86
  15. # define REGFORMAT "%08x"
  16. #else
  17. # define SIGSEGV_STACK_GENERIC
  18. # define REGFORMAT "%x"
  19. #endif

  20. static void signal_segv(int signum, siginfo_t* info, void*ptr) {
  21.         static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};

  22.         size_t i;
  23.         ucontext_t *ucontext = (ucontext_t*)ptr;

  24. #if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
  25.         int f = 0;
  26.         Dl_info dlinfo;
  27.         void **bp = 0;
  28.         void *ip = 0;
  29. #else
  30.         void *bt[20];
  31.         char **strings;
  32.         size_t sz;
  33. #endif

  34. #if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
  35. # if defined(SIGSEGV_STACK_IA64)
  36.         ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
  37.         bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
  38. # elif defined(SIGSEGV_STACK_X86)
  39.         ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
  40.         bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
  41. # endif

  42.         fprintf(stderr, "Stack trace:\n");
  43.         while(bp && ip) {
  44.                 if(!dladdr(ip, &dlinfo))
  45.                         break;

  46.                 const char *symname = dlinfo.dli_sname;

  47.                 fprintf(stderr, "% 2d: %p %s+%u (%s)\n",
  48.                                 ++f,
  49.                                 ip,
  50.                                 symname,
  51.                                 (unsigned)(ip - dlinfo.dli_saddr),
  52.                                 dlinfo.dli_fname);

  53.                 if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main"))
  54.                         break;

  55.                 ip = bp[1];
  56.                 bp = (void**)bp[0];
  57.         }
  58. #else
  59.         fprintf(stderr, "Stack trace (non-dedicated):\n");
  60.         sz = backtrace(bt, 20);
  61.         strings = backtrace_symbols(bt, sz);

  62.         for(i = 0; i < sz; ++i)
  63.                 fprintf(stderr, "%s\n", strings[i]);
  64. #endif
  65.         fprintf(stderr, "End of stack trace\n");
  66.         return;
  67. }
  68. int setup_sigsegv() {
  69.         struct sigaction action;
  70.         memset(&action, 0, sizeof(action));
  71.         action.sa_sigaction = signal_segv;
  72.         action.sa_flags = SA_SIGINFO;
  73.         if(sigaction(SIGUSR1, &action, NULL) < 0) {
  74.                 perror("sigaction");
  75.                 return 0;
  76.         }

  77.         return 1;
  78. }



  79. void func1()
  80. {
  81.         raise(SIGUSR1);
  82.         return ;

  83. }
  84. void func2()
  85. {
  86.         raise(SIGUSR1);
  87.         return ;

  88. }

  89. void entry()
  90. {
  91.         func1();
  92.         func2();
  93.         return;
  94. }
  95. int main()
  96. {
  97.         setup_sigsegv();
  98.         entry();
  99. }
复制代码

gcc -o funstack -rdynamic -ldl funstack.c
初步看来还不错有空加到我原来俄内存检测程序中看看效果

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多