需要已掌握:动态符号表、符号表相关内容

backtrace, backtrace_symbols, backtrace_symbols_fd - 用于支持应用程序自调试

提要

#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);

描述

backtrace() 用于获取调用程序的堆栈。获取的堆栈信息存放在参数buffer中,它是一个指针数组。堆栈表示程序对该函数的一连串的调用。buffer指向的数组中的每一项都是void*类型,存放的是来自相应堆栈帧的返回地址。size参数指定了buffer中最多可存放几个地址。backtrace() 函数的返回值是实际获取的指针个数,最大不超过size大小。如果堆栈大小大于size指定的值,则只能获取到最近调用该函数的部分堆栈帧地址;为了获得完整的堆栈,请确保buffersize设置的足够大。

给定backtrace()buffer返回的地址集,backtrace_symbols()可以将地址转为用符号地址描述的字符串数组。size参数指定了该字符串数组中包含的地址数(即backtrace()的返回值)。每个符号地址中包含了函数名(如果可以确定的话),十六进制的函数偏移量和十六进制的实际返回地址。backtrace_symbols()的返回值是一个指向字符串数组的指针,它的大小和buffer相同。该数组的内存是backtrace_symbols()分配的(调用malloc),并且必须被调用者释放(free)。(指针数组指向的字符串不需要也不应该被释放。)

backtrace_symbols()返回的字符串都是malloc出来的,但是不要最后一个一个的free,因为backtrace_symbols()是根据backtrace()给出的堆栈层数,一次性的malloc出来一块内存来存放结果字符串的。所以,像示例中的代码一样,只需要在最后,freebacktrace_symbols()的返回指针就OK了。

backtrace_symbols_fd()采用与backtrace_symbols()相同的buffersize参数,但它不向调用方返回字符串数组,而是将字符串(每行一个)写入文件描述符fdbacktrace_symbols_fd()不调用malloc,因此可以在调用该函数可能发生失败的情况下使用,具体请参见注意

返回值

backtrace()返回buffer中返回的地址数,该地址数<=size指定的大小。如果返回值小于size,则存储完整堆栈;如果它等于size,则它可能已被截断,在这种情况下,可能不会返回最开始堆栈帧的地址。

成功时,backtrace_symbols()返回一个指向调用者所分配的数组的指针;失败时,返回NULL。

属性

Interface Attribute Value
backtrace() Thread safety MT-Safe
backtrace_symbols() Thread safety MT-Safe
backtrace_symbols_fd() Thread safety MT-Safe

注意

这些函数对函数的返回地址如何存储在堆栈上进行了一些假设。注意以下几点:

  • Omission of the frame pointers (as implied by any of gcc’s nonzero optimization levels) may cause these assumptions to be violated.(删除堆栈帧指针会导致无法正确解析堆栈内容)
  • 内联函数没有堆栈帧。
  • 尾部调用优化会导致一个堆栈帧替换另一个堆栈帧。
  • backtrace()backtrace_symbols_fd()不显式调用malloc(),但它们是libgcc的一部分,libgcc第一次使用时会动态加载。动态加载通常会触发对malloc的调用。如果需要对这两个函数进行某些调用而不分配内存(例如,在信号处理程序中),则需要确保事先加载libgcc
  • 某些编译器的优化选项对获取正确的调用堆栈有干扰

例子

下面的程序演示了backtrace()backtrace_symbols_fd()的使用。下面的shell会话显示了运行程序时可能看到的内容:

#include <execinfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>#define BT_BUF_SIZE 100void myfunc3(void)
{int j, nptrs;void *buffer[BT_BUF_SIZE];char **strings;nptrs = backtrace(buffer, BT_BUF_SIZE);printf("backtrace() returned %d addresses\n", nptrs);// 下方整个实现打印堆栈的代码可以用一行代码代替,即// backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO);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 的作用是不导出符号,即在打印堆栈时不显示该函数名“myfunc2”
static void myfunc2(void)
{myfunc3();
}void myfunc(int ncalls)
{if (ncalls > 1)myfunc(ncalls - 1);elsemyfunc2();
}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);
}

编译并运行:

# 在使用GNU ld的系统中,为了支持函数名功能,需要传递-rdynamic标志给链接器
cc -rdynamic prog.c  -o prog

运行结果

具体参见

man 3 backtrace

backtrace, backtrace_symbols, backtrace_symbols_fd相关推荐

  1. 利用ptrace和memfd_create混淆程序名和参数

    <GDB调试之ptrace实现原理> <C语言程序调用栈:backtrace+backtrace_symbols+backtrace_symbols_fd> <strac ...

  2. Linux环境无文件渗透执行ELF:memfd_create、ptrace

    <GDB调试之ptrace实现原理> <C语言程序调用栈:backtrace+backtrace_symbols+backtrace_symbols_fd> <strac ...

  3. strace实现原理:ptrace系统调用

    <GDB调试之ptrace实现原理> <C语言程序调用栈:backtrace+backtrace_symbols+backtrace_symbols_fd> 目录 strace ...

  4. java打印堆栈信息linux,在C/C++程序里打印调用栈信息(转载)

    原文出处  http://blog.csdn.net/yetyongjin/article/details/7759144 以下不能windows + mingw下执行.  windows下参考 ht ...

  5. 内存访问错误造成Segmentation fault (SIGSEGV)

    linux下程序对SIGSEGV信号的默认处理方式是产生coredump并终止程序,可以参考man 7 signal Signal     Value     Action   Comment ─── ...

  6. linux SIGSEGV信号 内存访问错误 Segmentation fault

    linux下程序对SIGSEGV信号的默认处理方式是产生coredump并终止程序,可以参考man 7 signal Signal     Value     Action   Comment ─── ...

  7. Linux ptrace系统调用详解:利用 ptrace 设置硬件断点

    <GDB调试之ptrace实现原理> <C语言程序调用栈:backtrace+backtrace_symbols+backtrace_symbols_fd> <strac ...

  8. c/c++ backtrace打印函数调用栈

    效果 解析动态库libtest.so和可执行文件m: 打印原始栈 #include <execinfo.h> void *array[32] = {0};size_t size;char ...

  9. Debug Hacks中文版——深入调试的技术和工具

    关键词:gdb.strace.kprobe.uprobe.objdump.meminfo.valgrind.backtrace等. <Debugs Hacks中文版--深入调试的技术和工具> ...

  10. 怎么编写段错误(Segmentation fault)的程序

    On Unix-like operating systems, a process that accesses invalid memory receives the SIGSEGV signal. ...

最新文章

  1. 基于JSP实现人力资源管理系统
  2. 图解 HTTP 笔记(四)——HTTP 状态码
  3. hdu2570(贪心)
  4. 8.Boost之unordered_set
  5. 操作软件_如何提升办公软件的操作能力
  6. python tensorflow 智能家居_TensorFlow平台下的视频目标跟踪深度学习模型设计
  7. php去掉字符串末尾数字,PHP-RegEx:删除字符串末尾的数字,并删除特定字符串后的文本...
  8. 计算机教师招聘试题(汇总集合版),计算机教师招聘试题(汇总集合版)ed.doc
  9. ORM框架之Spring Data JPA(二)spring data jpa方式的基础增删改查
  10. JSK-391 公约公倍【入门】
  11. 如何按照页面载入进度制作进度条??
  12. java编译及运行过程_简述JAVA程序的编辑编译和运行过程
  13. [Java学习] BFS算法示例
  14. 戴尔服务器u盘装系统看不见磁盘,戴尔电脑u盘装系统找不到硬盘怎么解决
  15. docker run参数-v的rw、ro详解
  16. Github-谷歌插件gitzip(加速器-不用再忍受几十kb/s的煎熬了)
  17. Unresolved compilation problem,问题
  18. torch.sequeeze 和 torch.unsequeeze 的用法
  19. win10系统没声音 服务器,win10电脑突然没有声音的10种修复方法
  20. index.php g wap,index.php?g=Wap

热门文章

  1. python 切片器_excel和python中的切片器列表
  2. matlab 传函将s换为jw,2010MATLAB及控制系统仿真_总复习.ppt
  3. 为互连智能合约Connected Contracts使用Axelar SDK
  4. 【智能家居】空调遥控器破解
  5. 安全牛--kali学习笔记
  6. Android setLayoutparams失效几个原因
  7. MySQL系列之STRAIGHT JOIN用法简介
  8. DEV 报表设计分组
  9. 韦东山嵌入式linux第一期_裸机实战之开发板熟悉与体验篇
  10. 三国志战略版:北定中原剧本个性加点指引