我们知道,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. Navicat 的使用(二)

    一,navicat如何写sql语句查询? 方法1:ctrl+q就会弹出一个sql输入窗口,就可以在里面写sql了.写完sql后,直接ctrl+r就执行sql了. 还有一点,写sql语句时,navica ...

  2. Java递归算法——三角数字

    import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.i ...

  3. Android学习笔记——TableLayout

    该工程的功能是实现在一个activity中显示一个表格 以下代码是MainActivity.java中的代码 package com.example.tablelayout; import andro ...

  4. 知乎布局||offsetTop||侧边栏自动等高

    1.对a标签的详细介绍 直接在a标签使用onclick,怎么去除a的默认链接,onclick="return test()" 注意这里的return 不可舍去,test函数可以直接 ...

  5. php Hash Table(一) Hash Table的结构

    关于Hash Table专题: 一直想深入理解一下php的hash table的实现,以前一直是星星点点的看看,从未彻底的总结过,那就从这个专题开始吧! 主要想总结几个部分:hashtable结构,h ...

  6. jar tvf study.war jar命令查看war/jar包的内容

    jar tvf study.war 0 Thu Oct 20 14:01:18 CST 2016 META-INF/ 137 Thu Oct 20 14:01:16 CST 2016 META-INF ...

  7. Orchard源码分析(4.4):Orchard.Caching.CacheModule类

    概述 CacheModule也是一个Autofac模块.   一.CacheModule类 CacheModule将DefaultCacheManager注册为ICacheManager:       ...

  8. html、css杂记

    1:浮动 <div style="float: left"> 2:清除浮动,把父div撑起来 <div style="clear:both"& ...

  9. F5负载均衡的初识和基本配置

    目前全球范围内应用比较广泛的负载均衡设备为美国的F5.F5于2000年底进驻中国,在国内业界,F5负载均衡产品已经成为了主流负载均衡技术的代名词.下面我们对F5负载均衡设备做一个基本介绍,方便大家去认 ...

  10. ADB常用命令(Android Debug Bridge)

    首先要配置环境变量. adb devices 列出所有的设备 adb start-server 开启adb服务 adb kill-server    关闭adb服务 adb logcat    查看L ...