我们知道,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);

}

staticvoid  /* "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]

这回,可以看到函数名了。是不是很酷呢?

在c或c+程序里打印调用栈。转的更多相关文章

  1. 在C/C++程序里打印调用栈信息

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

  2. android打印调用栈

    在某些机器上,不能下断点,出现了某个诡异的问题,想到唯一的解决方式,就是打印调用栈了,google发现这个,记录下,以后备用 Log.d(",Log.getStackTraceString( ...

  3. kernel中,dump_stack打印调用栈,print_hex_dump打印一片内存,记录一下

    kernel中,dump_stack打印调用栈,print_hex_dump打印一片内存,记录一下

  4. 利用backtrace和backtrace_symbols函数打印调用栈信息

    在头文件"execinfo.h"中声明了三个函数用于获取当前线程的函数调用堆栈. #include <execinfo.h>  int backtrace(void * ...

  5. perf打印调用栈的过程

    perf_prepare_sample-->perf_callchain-->get_perf_callchain 上面的调用栈会使用 perf_event_output--> 0x ...

  6. java 中打印调用栈

    source-code: public class A { public A() {} private static void printStackTrace() {         StackTra ...

  7. python 打印调用栈

    import traceback def BBQ(): traceback.print_stack() 引入 traceback 包,在某个函数中执行 traceback.print_stack().

  8. arm平台的调用栈回溯(backtrace)

    title: arm平台的调用栈回溯(backtrace) date: 2018-09-19 16:07:47 tags: --- 介绍 arm平台的调用栈与x86平台的调用栈大致相同,稍微有些区别, ...

  9. Lua中如何实现类似gdb的断点调试--03通用变量修改及调用栈回溯

    在前面两篇01最小实现及02通用变量打印中,我们已经实现了设置断点.删除断点及通用变量打印接口. 本篇将继续新增两个辅助的调试接口:调用栈回溯打印接口.通用变量设置接口.前者打印调用栈的回溯信息,后者 ...

随机推荐

  1. (翻译)如何对python dict 类型按键(keys)或值(values)排序

    如何对dict类型按键(keys)排序(Python 2.4 或更高版本): mydict = {'carl':40, 'alan':2, 'bob':1, 'danny':3} for key in ...

  2. Git删除tag

    git tag -d v2016062101 删除本地tag git push origin --delete tag v2016062101 删除远程tag

  3. Git创建ssh-key

    打开git bash界面,输入: ssh-keygen -t rsa -C "yourname@email.com" 一路回车,后续保持默认值即可. 把C:\users\yourn ...

  4. C#------如何取出exe运行文件给客户使用

    1.将解决方案配置里面的“Debug”转换成“Release” 2.右击“解决方案”,选着“重新生成解决方案”,以得到最新的版本 3.找到工程目录下的“bin”文件夹,里面有“Release”文件夹, ...

  5. spark geoip

    import java.io.File import scala.io.Source import com.sanoma.cda.geoip.MaxMindIpGeo import com.sanom ...

  6. springmvc @responseBody自动打包json出现错误(外键查询死循环)问题

    在外键字段的get方法上加入@JsonIgnore

  7. JavaWeb学习笔记——开发动态WEB资源(一)Java程序向浏览器输出数据

    开发一个动态web资源,即开发一个Java程序向浏览器输出数据,需要完成以下2个步骤: 1.编写一个Java类,实现Servlet接口 开发一个动态web资源必须实现javax.servlet.Ser ...

  8. 第4章 jQuery的事件和动画(二)

    二. jQuery中的动画 动画在前面几章案例中是回避不了的问题.此处结合一些简便的写法稍作系统的分析. 1. show()和hide()(1)介绍——不用过多的介绍了jQuery最基本的方法.本质是 ...

  9. wampserver 2.5安装pear win8.1

    集成环境的悲伤啊~ 本来看到pear想试试 结果发现根本没有go-pear.bat 自己的环境 都是 系统win 8.1 php 5.5.12 mysql  5.6.17 apache 2.4.9   ...

  10. 史上最全的maven pom.xml文件教程详解

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...