c中如何打印函数调用堆栈? 如何在一个函数中打印出来调用它的上一级函数名称?
比如在做内存泄漏检测的时候,发现只打印分配内存点的信息还不够,因为有时候有多个流程同时调用一个地方分配内存,最好能是象gdb那样打印出函数调用的堆栈来更方便一些。
如果是c++还能想到用抛出异常来尝试一下,c里面有什么好方法么?
原帖由 feasword 于 2007-6-17 20:06 发表
如题
如何在一个函数中打印出来调用它的上一级函数名称?
比如在做内存泄漏检测的时候,发现只打印分配内存点的信息还不够,因为有时候有多个流程同时调用一个地方分配内存,最好能是象gdb那样打印出函数调用的 ...
何不直接参考 gdb 的源码?
原帖由 feasword 于 2007-6-17 20:06 发表
如题
如何在一个函数中打印出来调用它的上一级函数名称?
比如在做内存泄漏检测的时候,发现只打印分配内存点的信息还不够,因为有时候有多个流程同时调用一个地方分配内存,最好能是象gdb那样打印出函数调用的 ... - func1(....)
- {
- .....
- #ifdef MYFEBUG
- func2(....,__func__);
- #endif
- ....
- }
- #ifdef MYFEBUG
- func2(....,const char* funcname)
- #else
- func2(...)
- #endif
- {
- #ifdef MYFEBUG
- printf("%s:%s\n",__func__,funcname);
- #endif
- ....
- }
可以参考strace,我好像还用过一个什么trace。。。。的
这问题C版ms讨论了很多次了,info gcc
__builtin_return_address
__builtin_frame_address
还有一个相关的, info libc
glibc中,
backtrace
backtrace_symbols
试验了一下,好像只能打印出地址,但是有函数名更方便些
在11楼的提示下在网上找了篇文章,自己裁减了一下
- //funstack.c
- #define _GNU_SOURCE
- #include <memory.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <signal.h>
- #include <ucontext.h>
- #include <dlfcn.h>
- #include <execinfo.h>
- #if defined(REG_RIP)
- # define SIGSEGV_STACK_IA64
- # define REGFORMAT "%016lx"
- #elif defined(REG_EIP)
- # define SIGSEGV_STACK_X86
- # define REGFORMAT "%08x"
- #else
- # define SIGSEGV_STACK_GENERIC
- # define REGFORMAT "%x"
- #endif
- static void signal_segv(int signum, siginfo_t* info, void*ptr) {
- static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};
- size_t i;
- ucontext_t *ucontext = (ucontext_t*)ptr;
- #if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
- int f = 0;
- Dl_info dlinfo;
- void **bp = 0;
- void *ip = 0;
- #else
- void *bt[20];
- char **strings;
- size_t sz;
- #endif
- #if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
- # if defined(SIGSEGV_STACK_IA64)
- ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
- bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
- # elif defined(SIGSEGV_STACK_X86)
- ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
- bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
- # endif
- fprintf(stderr, "Stack trace:\n");
- while(bp && ip) {
- if(!dladdr(ip, &dlinfo))
- break;
- const char *symname = dlinfo.dli_sname;
- fprintf(stderr, "% 2d: %p %s+%u (%s)\n",
- ++f,
- ip,
- symname,
- (unsigned)(ip - dlinfo.dli_saddr),
- dlinfo.dli_fname);
- if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main"))
- break;
- ip = bp[1];
- bp = (void**)bp[0];
- }
- #else
- fprintf(stderr, "Stack trace (non-dedicated):\n");
- sz = backtrace(bt, 20);
- strings = backtrace_symbols(bt, sz);
- for(i = 0; i < sz; ++i)
- fprintf(stderr, "%s\n", strings[i]);
- #endif
- fprintf(stderr, "End of stack trace\n");
- return;
- }
- int setup_sigsegv() {
- struct sigaction action;
- memset(&action, 0, sizeof(action));
- action.sa_sigaction = signal_segv;
- action.sa_flags = SA_SIGINFO;
- if(sigaction(SIGUSR1, &action, NULL) < 0) {
- perror("sigaction");
- return 0;
- }
- return 1;
- }
- void func1()
- {
- raise(SIGUSR1);
- return ;
- }
- void func2()
- {
- raise(SIGUSR1);
- return ;
- }
- void entry()
- {
- func1();
- func2();
- return;
- }
- int main()
- {
- setup_sigsegv();
- entry();
- }
复制代码
gcc -o funstack -rdynamic -ldl funstack.c
初步看来还不错有空加到我原来俄内存检测程序中看看效果
|