我们知道,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+程序里打印调用栈。转

    在C/C++程序里打印调用栈信息 我们知道,GDB的backtrace命令可以查看堆栈信息.但很多时候,GDB根本用不上.比如说,在线上环境中可能没有GDB,即使有,也不太可能让我们直接在上面调试.如 ...

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

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

  3. android打印调用栈

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

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

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

  5. perf打印调用栈的过程

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

  6. Android 中调试手段 打印函数调用栈信息

    下面来简单介绍下 android 中的一种调试方法. 在 android 的 app 开发与调试中,经常需要用到打 Log 的方式来查看函数调用点. 这里介绍一种方法来打印当前栈中的函数调用关系 St ...

  7. java 中打印调用栈

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

  8. python 打印调用栈

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

  9. Python错误 -- try/except/finally 、调用栈、记录错误、抛出错误

    Bug:程序编写有问题造成的错误,称之为Bug.    debug:调试 注意:bug是程序本身有问题.有缺陷.系统漏洞 异常:完全无法在程序运行中预测的错误,例如写入文件的时候,磁盘满了,写不进去了 ...

随机推荐

  1. iOS简易柱状图(带动画)--新手入门篇

    叨逼叨 好久没更新博客了,才几个月,发生了好多事情,处理了好多事情.不变的是写代码依然在继续. 做点啥子 看看objective-c的书,学着写了个柱状图,只是练习的demo而已,iOS上的图表控件已 ...

  2. (旧)子数涵数·PS ——翻页效果

    一.首先在网络上下载一张图片,作为素材.这是我下载的素材,至于为什么选择这张照片呢,当然不是因为自己的一些羞羞的念头啦. 二.打开Photoshop,我使用的版本是CS3(因为CS3所占的磁盘空间较小 ...

  3. Moqui学习之数据与资源

    资源位置: 资源门面位置的字符串类似于URL的构成方式:协议,主机,可选端口和文件名.它支持标准的java URL协议(http https ftp jar file).同样也支持一些扩展的协议: c ...

  4. c++ 中 delete p与 delete []p的区别

    #include <cstdio> class A{private: int i;public: ~A() { printf("hi"); }};void d(A *) ...

  5. WordPress Option API(数据库储存 API)

    WordPress Option API 是提供给开发者的数据库存储机制,通过调用函数,可以快速.安全的把数据存储到数据库里(都在 wp_options 表). 每个设置的模式是 key – valu ...

  6. [转]Java静态方法为什么不能访问非静态方法

    非静态方法(不带static)可以访问静态方法(带static),但是反过来就不行,为什么呢? ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 publi ...

  7. Java基础-常量,变量,成员变量,局部变量

    在java中,数据是以常量和变量两种方法形式进行存储和表示的(实际上,所有程序的数据都是这两种形式). 变量 变量代表程序的状态.程序通过改变变量的值来改变整个程序的状态,或者说得更大一些,也就是实现 ...

  8. 图解Android - Android GUI 系统 (5) - Android的Event Input System

    Android的用户输入处理 Android的用户输入系统获取用户按键(或模拟按键)输入,分发给特定的模块(Framework或应用程序)进行处理,它涉及到以下一些模块: Input Reader: ...

  9. Ecshop /admin/get_password.php Password Recovery Secrect Code Which Can Predict Vulnerability

    目录 . 漏洞描述 . 漏洞触发条件 . 漏洞影响范围 . 漏洞代码分析 . 防御方法 . 攻防思考 1. 漏洞描述 Ecshop提供了密码找回功能,但是整个密码找回流程中存在一些设计上的安全隐患 . ...

  10. Codeforces 295A Greg and Array

    传送门 A. Greg and Array time limit per test 1.5 seconds memory limit per test 256 megabytes input stan ...