我们知道,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. Object C学习笔记18-SEL,@ selector,Class,@class

    本章是对上一章<<Object C学习笔记17-动态判断和选择器>>的一点补充,所以比较简单点. 一. SEL 类型 在上一篇介绍了几个方法,都只是介绍了其使用方式但是没有具体 ...

  2. node 日志

    我们主动控制的log4js,还有一些日志是继承好的,错误日志了,进程日志了,请求日志了. 1. var express = require('express');var logger = requir ...

  3. jQuery找兄弟系列next(),nextAll(),nextUntil(),prev(),prevAll(),prevUntil(),siblings()

    <body> <div id="main"> <div id="hot" class="rightbar"&g ...

  4. 【BZOJ1006】【HNOI2008】神奇的国度(弦图染色)

    1006: [HNOI2008]神奇的国度 Time Limit: 20 Sec  Memory Limit: 162 MBSubmit: 1467  Solved: 603[Submit][Stat ...

  5. JavaScript基础---语言基础(3)

    流程控制语句 学习要点: 1.switch语句 2.for...in语句 3.break和continue语句 4.with语句 ECMA-262规定了一组流程控制语句.语句定义了ECMAScript ...

  6. DELL R720系统内存指南

    该文章摘自于:http://www.dell.com/support/article/cn/zh/cndhs1/SLN153646/zh#issue3,仅供个人作为笔记使用 PowerEdge R72 ...

  7. 利用css3实现超出文本指定行数与省略号效果

    <style> .text1 {/*单行*/ width:200px; overflow:hidden; text-overflow:ellipsis; -o-text-overflow: ...

  8. 利用HTML5的Video进行视频截图并保存到本地

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  9. Nginx简单实现网站的负载均衡

    在大型网站搭建时,都会考虑如果用户量每日不断增加,大量的并发访问,会不会给网站.数据库带来崩盘的灾难.今天我们就讨论一下,现实中如何解决这些问题的一套最为容易实现的方案. 控制并发,大家都会首先考虑的 ...

  10. 【CodeForces 625C】K-special Tables

    题意 把1到n*n填在n*n的格子里.要求每一行都是递增的,使第k列的和最大. 分析 第k列前的格子1 2 .. 按要求填到满格,然后第k列及后面的格子,都从左到右填递增1的数. 第k列的和再加起来, ...