Linux x86_64 backtrace 栈回溯

文章目录

  • 前言
  • 一、demo演示
  • 二、函数解析
    • 2.1 backtrace函数
    • 2.2 backtrace_symbols

前言

Linux x86_64 基于FP栈回溯请参考:Linux x86_64 dump_stack()函数基于FP栈回溯

回溯(backtrace)是指当前线程中正在活动的函数调用列表。通常情况下,检查程序的回溯信息是通过使用外部调试器(如 gdb)来实现的。然而,有时候从程序内部以编程方式获取回溯信息也是很有用的,例如用于日志记录或诊断目的。

头文件 execinfo.h 声明了三个函数,用于获取和操作当前线程的回溯信息。

NAMEbacktrace, backtrace_symbols, backtrace_symbols_fd - support for application self-debuggingSYNOPSIS#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);

一、demo演示

#include <stdio.h>
#include <execinfo.h>
#include <stdlib.h>#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))void dump_stack(void)
{//定义一个 void 类型的指针数组 array,用于存储返回地址。void *array[16];//使用 backtrace 函数获取当前程序的函数调用栈信息,并将返回地址存储在 array 数组中。//返回实际存储的返回地址数量size。size_t size = backtrace(array, ARRAY_SIZE(array));//使用 backtrace_symbols 函数,将返回地址数组 array 和大小 size 作为参数,获取每个返回地址对应的函数名称,并将函数名称字符串数组的指针存储在 strings 中。char **strings = backtrace_symbols(array, size);size_t i;//打印获取到的函数调用栈帧的数量,即 size。printf("Obtained %zd stack frames.\n", size);//遍历 strings 数组,逐行打印每个函数名称以及相关栈回溯信息。for (i = 0; i < size; i++)printf("%s\n", strings[i]);free(strings);
}void func_c(void)
{dump_stack();	
}void func_b(void)
{func_c();	
}void func_a(void)
{func_b();
}int main()
{func_a();return 0;
}
# gcc backtrace.c
# ./a.out
Obtained 7 stack frames.
./a.out() [0x40067c]
./a.out() [0x400701]
./a.out() [0x40070c]
./a.out() [0x400717]
./a.out() [0x400722]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7f93f0d3e555]
./a.out() [0x400599]# gcc -rdynamic backtrace.c
# ./a.out
Obtained 7 stack frames.
./a.out(dump_stack+0x1f) [0x4008ec]
./a.out(func_c+0x9) [0x400971]
./a.out(func_b+0x9) [0x40097c]
./a.out(func_a+0x9) [0x400987]
./a.out(main+0x9) [0x400992]
/lib64/libc.so.6(__libc_start_main+0xf5) [0x7fec54d7d555]
./a.out() [0x400809]

要取符号名称。对于使用 GNU 链接器的系统,需要使用 -rdynamic 链接器选项:

-rdynamicPass 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 symboltable. This option is needed for some uses of "dlopen" or to allow obtaining backtraces from within a program.

-rdynamic 是一个编译器选项,它会在支持的目标平台上将 -export-dynamic 标志传递给 ELF 链接器。这指示链接器将所有符号(而不仅仅是被使用的符号)添加到动态符号表中。

这个选项在某些情况下非常有用,特别是在以下两个方面:

(1)dlopen 函数的使用:dlopen 是一个动态链接库加载函数,它允许在程序运行时加载和链接共享库。当使用 dlopen 动态加载共享库时,如果需要从加载的库中调用函数,那么这些函数的符号必须在动态符号表中。通过使用 -rdynamic 选项,可以将所有符号(包括未被程序直接使用的符号)添加到动态符号表中,使得动态加载的库能够正确地解析和调用这些符号。

(2)在程序内部获取回溯信息:回溯(backtrace)是指在程序执行期间获取函数调用栈的信息。当使用像 backtrace 或 backtrace_symbols 这样的函数时,需要访问所有函数的符号信息,而不仅仅是已使用的符号。通过使用 -rdynamic 选项,可以确保所有符号都包含在动态符号表中,从而使得获取回溯信息时能够正确地解析函数名称。

二、函数解析

NAMEbacktrace, backtrace_symbols, backtrace_symbols_fd - support for application self-debuggingSYNOPSIS#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);

2.1 backtrace函数

 int backtrace(void **buffer, int size);

backtrace() 函数返回调用程序的函数调用栈,将其填充到由 buffer 指向的数组中。函数调用栈是指当前程序中正在活动的函数调用序列。buffer 数组中的每个项都是 void* 类型,表示对应堆栈帧的返回地址。

size 参数指定了 buffer 数组中可以存储的地址的最大数量。如果函数调用栈超过了指定的 size,那么将返回与最近的 size 个函数调用相对应的地址;若要获取完整的函数调用栈,请确保 buffer 和 size 足够大。

换句话说,如果函数调用栈超过了给定的 size,则最旧的函数调用将被截断,只有最近的函数调用的地址将存储在 buffer 中。如果需要完整的函数调用栈信息,应提供足够大的 buffer 和 size。

其声明:

/* Store up to SIZE return address of the current program state inARRAY and return the exact number of values stored.  */
extern int backtrace (void **__array, int __size) __nonnull ((1));

backtrace函数的目的是将当前程序状态的返回地址存储在指定大小的数组中,并返回实际存储的返回地址数量。

返回类型:int,表示返回的是一个整数值,即实际存储的返回地址数量
参数:有两个参数
void **__array:指向 void* 类型的指针数组的指针,用于存储返回地址
int __size:表示存储空间的大小,即数组的大小
函数属性:__nonnull ((1)) 表示第一个参数 __array 不能为空指针

backtrace 函数是一个在调试和错误排查过程中常用的函数,它可以用于获取当前程序的函数调用栈信息。

该函数的作用是在运行时获取当前程序的返回地址,并将这些地址存储在指定的数组中。返回地址表示程序执行到当前位置时将要返回的地址,也就是当前函数执行完后将要执行的下一条指令的地址。

通过获取返回地址,并将其存储在数组中,我们可以构建一个表示函数调用栈的数据结构。函数调用栈是一个记录函数调用关系的堆栈结构,每个堆栈帧表示一个函数调用,其中包含函数的返回地址和相关的参数和局部变量等信息。

2.2 backtrace_symbols

char **backtrace_symbols(void *const *buffer, int size);

backtrace_symbols() 函数将由 buffer 返回的地址集合转换为一个字符串数组,用于以符号方式描述这些地址。size 参数指定了 buffer 中地址的数量。每个地址的符号表示包括函数名称(如果可以确定)、函数的十六进制偏移量以及实际的返回地址(以十六进制表示)。backtrace_symbols() 的函数结果是指向字符串指针数组的地址。该数组是由 backtrace_symbols() 动态分配的内存块,需要由调用者使用 free() 函数进行释放。(指针数组指向的字符串本身不需要也不应该被释放。)

使用 backtrace_symbols() 函数,可以将返回的地址转换为可读性更好的字符串形式,以便更方便地理解和分析函数调用栈信息。

需要注意的是,返回的字符串数组是通过 malloc() 动态分配的内存块,因此需要在使用完毕后手动释放,以避免内存泄漏。

其声明:

/* Return names of functions from the backtrace list in ARRAY in a newlymalloc()ed memory block.  */
extern char **backtrace_symbols (void *const *__array, int __size)__THROW __nonnull ((1));

backtrace_symbols函数用于从给定的返回地址数组中获取函数名称,并将这些函数名称以字符串数组的形式返回。

返回类型:char **,表示返回一个指向字符指针的指针,即字符串数组的指针
参数:有两个参数
void *const *__array:指向 void* 类型的指针数组的指针,用于存储返回地址
int __size:表示存储返回地址的数组的大小
函数属性:__THROW 表示函数不会抛出异常,__nonnull ((1)) 表示第一个参数 __array 不能为空指针

backtrace_symbols 函数是一个用于获取函数调用栈信息中函数名称的常用函数。它根据给定的返回地址数组,在新分配的内存块中动态生成一个字符串数组,其中每个字符串表示相应返回地址对应的函数名称。

函数调用栈是一个记录函数调用关系的堆栈结构,其中每个堆栈帧表示一个函数调用,包含函数的返回地址和其他相关信息。backtrace_symbols 函数可以通过返回地址数组来获取函数调用栈中每个函数的名称。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/10541.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通过物联网管理多台MQTT设备-基于米尔T527开发板

本篇测评由电子工程世界的优秀测评者“JerryZhen”提供。 本文将介绍基于米尔电子MYD-LT527开发板的网关方案测试。 一、系统概述 基于米尔-全志 T527设计一个简易的物联网网关&#xff0c;该网关能够管理多台MQTT设备&#xff0c;通过MQTT协议对设备进行读写操作&#xff0c;…

i春秋-Test

题目 解题 参考WP https://blog.csdn.net/qq_40654505/article/details/107142533/目录扫描 复现wp payload为&#xff1a; search.php?searchtype5&tid&areaeval($_POST[cmd])使用蚁剑连接 http://eci-2ze4iyhwj7xvb68bsb2t.cloudeci1.ichunqiu.com:80/search.ph…

python - pip安装及使用详解

pip 是 Python 的一个包管理器&#xff0c;它使安装和管理额外的库变得非常方便。通过 pip&#xff0c;你可以轻松地安装、升级、卸载 Python 包。下面将详细介绍如何在 Python 中使用 pip 进行安装及基本使用。 安装 pip 对于 Windows 用户&#xff1a; 较新版本的 Python&a…

在 Navicat 17 中探索表配置文件

距离 Navicat 17&#xff08;英文版&#xff09;的发布还有不到一周的时间&#xff0c;现在是深入研究新的表配置文件功能的最佳时机。它允许我们保存经常用于表的筛选、排序和列显示的不同组合。所以&#xff0c;事不宜迟&#xff0c;让我们开始吧&#xff01; 创建表配置文件…

leetcode——反转链表

206. 反转链表 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;创建三个指针n1,n2,n3&#xff0c;遍历原链表&#xff0c;通过三者之间的关系将链表反转。下面给出图示&#xff1a; 下面给出题解代码&#xff1a; typedef struct ListNode ListNode; struct List…

超分概述以及超分数据集

参考文献 数据集 数据集名称图像数量/张合成/真实数据集&#xff08;训练集/验证集/测试集图像格式图像内容T9191合成数据集&#xff08;训练集&#xff09;PNG包括动植物、人、车等局部纹理图像Timofte110合成数据集&#xff08;训练集&#xff09;PNG包括T91&#xff0c;Se…

Excel生成符合标准正态分布的随机数

在Excel中&#xff0c;生成符合标准正态分布的随机数可以使用NORM.INV()函数配合RAND()函数来实现。以下是具体的操作步骤&#xff1a; 使用RAND()函数生成均匀分布的随机数&#xff1a; RAND()函数会返回一个0到1之间的随机小数&#xff0c;包括0但不包括1。这代表了一个均匀分…

parallels desktop19最新免费Mac电脑虚拟机软件

Parallels Desktop是一款运行在Mac电脑上的虚拟机软件&#xff0c;它允许用户在Mac系统上同时运行多个操作系统&#xff0c;比如Windows、Linux等。通过这款软件&#xff0c;Mac用户可以轻松地在同一台电脑上体验不同操作系统的功能和应用程序&#xff0c;而无需额外的硬件设备…

自拍欺骗成为流行的身份证件欺诈技术

据 Socure 称&#xff0c;文档图像叠加是 2023 年最流行的身份证件欺诈技术&#xff0c;在所有被拒绝的身份证件中&#xff0c;有 63% 发生这种情况。 自拍欺骗和冒充在与文件相关的身份欺诈中占主导地位 当用户拍摄照片或使用 ID 的屏幕截图图像&#xff08;而不是提供文档的…

26、Flink 的状态数据结构升级

状态数据结构升级 a&#xff09;概述 Flink 流应用通常被设计为永远或者长时间运行&#xff0c;与所有长期运行的服务一样&#xff0c;应用程序需要随着业务的迭代而进行调整&#xff0c;应用所处理的数据 schema 也会随着进行变化。 升级状态类型的数据 schema &#xff0c…

探索 Docker Machine:打造无缝多平台容器部署的利器

在当今的软件开发和部署领域&#xff0c;容器化技术已经成为了一种不可或缺的利器&#xff0c;而 Docker Machine 则是这个强大生态系统中的一颗璀璨明珠。随着应用程序的不断发展和多样化&#xff0c;开发者们需要在不同的平台上进行部署&#xff0c;而 Docker Machine 提供了…

信息系统项目管理师(高项)--学习笔记【第2章:信息技术发展】

目录 第2章 信息技术发展2.1 信息技术及其发展2.1.1计算机软硬件2.1.2计算机网络2.1.3存储和数据库2.1.4信息安全2.1.5信息技术的发展 2.2 新一代信息技术及应用2.2.1物联网2.2.2云计算2.2.3大数据2.2.4区块链2.2.5人工智能2.2.6虚拟现实 第2章 信息技术发展 2.1 信息技术及其…

初始Java篇(JavaSE基础语法)(8)认识String类(上)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;JavaSE 简单介绍&#xff1a;在C语言中已经涉及到字符串了&#xff0c;但是在C语言中要表示字符串只能使用字符数组或者字符指针&#xff0c;可…

leetcode算法笔记-算法复杂度

对于时间复杂度&#xff0c;主要包括三种情况&#xff1a; 渐进紧确界&#xff1a; O渐进上界&#xff1a; 渐进下界&#xff1a; 加法原则&#xff1a;不同的时间复杂度相加取阶数最高的 乘法原则&#xff1a;不同的时间复杂度相乘&#xff0c;结果为时间复杂度的乘积 阶乘…

电脑nvidia驱动和合适版本的duda--自用 回忆版

参考文献&#xff1a;http://t.csdnimg.cn/ecDuG 内容很多抄的这个&#xff0c;主要害怕链接失效 一、Ubuntu 18.04 安装NVIDIA显卡驱动 1、查看本机显卡能够配置的驱动信息 ubuntu-drivers devices所以可以看出&#xff0c;推荐 nvidia-driver-530 - distro non-free 2、安…

Kubernetes学习-深入Pod篇(一) 创建Pod,Pod配置文件详解

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Kubernetes渐进式学习-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 1.前言 我们在前面的文章讲解了Kubernetes的核心概念和服务部署&#x…

MyBatis-plus(一):快速入门

目录 一、MyBatis-plus 快速入门 1、原理 2、实体类命名规则 3、常见注解 4、主键 id 策略 5、使用 TableField 的常见场景 6、常用配置 二、核心功能 1、条件构造器 2、自定义 SQL 3、IService 接口 一、MyBatis-plus 快速入门 1、原理 MyBatisPlus 通过扫描实体…

Spark写Hbase如何提高Bulkload的速度

​   对于Hbase的Bulkload基本流程这里就不多介绍可以看Bulkload流程介绍&#xff0c;本问主要介绍如何提升Bulkload的方式。   很多时候我们在写HFile的时候都会进行repartition使用的是repartitionAndSortWithinPartitions&#xff0c;其中Spark也提供几种repartition的实…

蓝桥杯备战6.奖学金

P1093 [NOIP2007 普及组] 奖学金 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) #include<bits/stdc.h> #define endl \n #define int long long using namespace std; const int N 2e710,M 1e310; int a[N],pre[N]; int chi[N],math[N],eng[N],id[N],b[N]; struct s…

算法学习012-不同路径 c++动态规划算法实现 中小学算法思维学习 信奥算法解析

目录 C不同路径 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、运行结果 五、考点分析 六、推荐资料 C不同路径 一、题目要求 1、编程实现 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09…