• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

(转载)在C/C++程序里打印调用栈信息

原作者: [db:作者] 来自: [db:来源] 收藏 邀请
(转载)http://blog.csdn.net/ctthunagchneg/article/details/8926543

我们知道,GDB的backtrace命令可以查看堆栈信息。但很多时候,GDB根本用不上。比如说,在线上环境中可能没有GDB,即使有,也不太可能让我们直接在上面调试。如果能让程序自己输出调用栈,那是最好不过了。本文介绍和调用椎栈相关的几个函数。

NAME
       backtrace, backtrace_symbols, backtrace_symbols_fd - support for application self-debugging

SYNOPSIS
       #include <execinfo.h>

       int backtrace(void **buffer, int size);

       char **backtrace_symbols(void *const *buffer, int size);

       void backtrace_symbols_fd(void *const *buffer, int size, int fd);

 

以上内容源自这几个函数的man手册。

 

先简单介绍一下这几个函数的功能:

l backtrace:获取当前的调用栈信息,结果存储在buffer中,返回值为栈的深度,参数size限制栈的最大深度,即最大取size步的栈信息。

l backtrace_symbols:把backtrace获取的栈信息转化为字符串,以字符指针数组的形式返回,参数size限定转换的深度,一般用backtrace调用的返回值。

l backtrace_symbols_fd:它的功能和backtrace_symbols差不多,只不过它不把转换结果返回给调用方,而是写入fd指定的文件描述符。

 

Man手册里,给出了一个简单的实例,我们看一下:

#include<execinfo.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>

void myfunc3(void)
{
   int j, nptrs;
   #define SIZE 100
   void *buffer[100];
   char **strings;

   nptrs = backtrace(buffer, SIZE);
   printf("backtrace() returned %d addresses\n", nptrs);

   /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
    *  would produce similar output to the following: */
 
   strings = backtrace_symbols(buffer, nptrs);
   if (strings == NULL) {
       perror("backtrace_symbols");
       exit(EXIT_FAILURE);
   }
 
   for (j = 0; j < nptrs; j++)
       printf("%s\n", strings[j]);
   free(strings);
}

static void  /* "static" means don't export the symbol... */
myfunc2(void)
{
   myfunc3();
}

void myfunc(int ncalls)
{
   if (ncalls > 1)
       myfunc(ncalls - 1);
   else
       myfunc2();
}

int main(int argc,char *argv[])
{
   if (argc != 2) {
       fprintf(stderr,"%s num-calls\n", argv[0]);
       exit(EXIT_FAILURE);
   }
   myfunc(atoi(argv[1]));

   exit(EXIT_SUCCESS);
}
编译:
# cc prog.c -o prog
运行:
# ./prog 0
backtrace() returned 6 addresses
./prog() [0x80485a3]
./prog() [0x8048630]
./prog() [0x8048653]
./prog() [0x80486a7]

这样,是输出了调用栈,不过只是以十六进制输出函数地址而已,可读性很差。仔细看下man手册,原来很简单,编译时加上个参数:

重新编译:

# cc -rdynamic  prog.c -o prog
通过gcc手册,我们可以也解下参数的说明:
-rdynamic
           Pass the flag -export-dynamic to the ELF linker, on targets that support it. 
This instructs the linker to add all symbols, not only used ones, to the dynamic symbol table.
This option is needed for some uses of "dlopen" or to allow obtaining backtraces from within a program. 再执行: # ./prog 0 backtrace() returned 6 addresses ./prog(myfunc3+0x1f) [0x8048763] ./prog() [0x80487f0] ./prog(myfunc+0x21) [0x8048813] ./prog(main+0x52) [0x8048867] /lib/libc.so.6(__libc_start_main+0xe6) [0xaf9cc6] ./prog() [0x80486b1] 这回,可以看到函数名了。是不是很酷呢?把它封装到你的调试代码中吧。

 

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
c#程序打包,同时把netframework也打包进去发布时间:2022-07-13
下一篇:
C#winform打开主界面并关闭登录界面发布时间:2022-07-13
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap