Linux 栈回溯

news2024/10/6 0:38:11

目录

  • 前言
  • 一、什么是栈回溯?
  • 二、栈回溯的实现原理
  • 三、参考阅读

前言

  日常工作中,我们在开发软件程序时,经常会遇到程序奔溃的问题,导致程序奔溃的原因有很多,我们一般都是定位到相关代码,再去查询具体原因。而定位到bug相关代码往往需要依赖栈回溯这个功能,知道程序是在哪里挂掉的。

一、什么是栈回溯?

  在Linux系统中,栈回溯(stack trace)是用于跟踪程序执行期间函数调用的一种技术,记录了程序在出现错误或异常时,从当前位置开始追溯回到程序的执行起点,包括每个函数的调用关系和相应的返回地址。栈回溯可以帮助开发人员快速定位问题所在。Linux系统提供了几种获取栈回溯的方法:

  1. backtrace函数:该函数定义在execinfo.h头文件中,可以获取当前线程的栈回溯信息。使用该函数需要在编译时添加-g选项以启用调试符号。使用方法:
#include <stdio.h>
#include <execinfo.h>
#include <stdlib.h>

void printStackTrace() {
  void *callstack[128];
  int i, frames;
  char **strs;

  frames = backtrace(callstack, 128);
  strs = backtrace_symbols(callstack, frames);
  
  printf("Stack Trace:\n");
  for (i = 0; i < frames; i++) {
    printf("%s\n", strs[i]);
  }
  
  free(strs);
}

void func1() {
  printf("Entering func1...\n");
  printStackTrace();
  printf("Exiting func1...\n");
}

void func2() {
  printf("Entering func2...\n");
  func1();
  printf("Exiting func2...\n");
}

void func3() {
  printf("Entering func3...\n");
  func2();
  printf("Exiting func3...\n");
}

int main() {
  printf("Entering main...\n");
  func3();
  printf("Exiting main...\n");

  return 0;
}

编译指令如下:

gcc -rdynamic stacktrace.c -o stacktrace
./stacktrace

通过添加 -rdynamic 参数,您将为可执行文件生成完整的符号表,从而使 backtrace_symbols 函数能够正确解析堆栈帧的信息。

  1. pstack命令:该命令可以打印指定进程或线程的栈回溯信息。为了使用 pstack 工具,您的系统必须安装有 gdb(GNU Debugger)。在大多数 Linux 发行版中,gdb 已经预装或可以通过包管理器轻松安装。pstack使用方法:
pstack <pid>
pstack -T <pid>
  1. gdb调试器:该调试器可以在程序崩溃时获取栈回溯信息。使用方法:
gdb <executable>
(gdb) run
<program crashes>
(gdb) bt

 无论使用哪种方法,栈回溯都可以提供关于程序崩溃或异常的有价值的信息,帮助开发人员快速定位问题所在。

二、栈回溯的实现原理

  在 Linux ARM64 系统上,实现栈回溯的原理与其他架构类似,主要涉及到寄存器、栈帧和符号表等概念。

  1. 寄存器:ARM64 架构有一组通用寄存器,用于存储函数调用的参数、局部变量和返回值等。在栈回溯过程中,关键的寄存器是程序计数器(Program Counter,PC),它保存着当前指令的地址。栈回溯需要从 PC 寄存器中获取每个函数调用的返回地址。
	ARM64 架构中的 CPU 寄存器是用于存储和处理数据的关键组件。寄存器在计算过程中用于存储
操作数、中间结果和控制信息。以下是 ARM64 架构中常见的 CPU 寄存器:

1. 通用寄存器(General-Purpose Registers):
   -3164 位的通用寄存器,用来存储整数类型数据。
   - 这些寄存器被用于算术运算、数据传输、函数参数传递和临时存储等。
   - 寄存器命名为 x0-x30,其中 x30(栈帧指针)一般作为函数的帧指针使用。

2. 程序计数器(Program Counter):
   - 存储当前执行的指令的地址。
   - 通常使用 `pc` 表示,是一个 64 位的寄存器。

3. 标志寄存器(Flags Register):
   - 存储运算结果的条件信息,例如是否溢出、是否相等等。
   - 在 ARM64 架构中,标志寄存器叫做 Condition Flags Register(CPSR)。

4. 浮点寄存器(Floating-Point Registers):
   -32128 位的浮点寄存器,用于存储浮点数和进行浮点运算。
   - 寄存器命名为 v0-v31,每个寄存器可以存储一个 128 位的浮点数或者多个较小精度的浮点数。

5. SIMD 寄存器(Single Instruction, Multiple Data Registers):
   -32128 位的 SIMD 寄存器,用于存储数据并执行 SIMD(单指令多数据)运算。
   - 在 ARM64 架构中,SIMD 寄存器被称为向量寄存器(Vector Registers)。
   - 寄存器命名为 v0-v31,每个寄存器可以存储一个 128 位的向量或者多个较小精度的元素。

	除了上述常见的寄存器之外,ARM64 架构还有一些特殊用途的寄存器,如堆栈指针寄存器
(Stack Pointer Register,SP)等。

	这些寄存器在程序的执行过程中起着重要的作用,用于处理数据、控制程序流程、传递参数等。
编程时,需要根据需求合理使用寄存器来优化性能和实现所需的功能。

在这里插入图片描述

	x0-x30 是 ARM64 架构中的通用寄存器,共有 31 个寄存器,用于存储整数类型数据以及执行
各种操作。下面对这些寄存器进行详细说明:

1. x0-x30 (x0~x30)- 这些寄存器是通用寄存器,每个寄存器的大小为 64 位。
   - 在函数调用中,寄存器 x0-x7 用于函数参数的传递,后续的参数(这几个寄存器存满了)存储在栈上。
   - 寄存器 x8 保留给系统调用使用。
   - 寄存器 x9-x15 可用作临时寄存器。
   - 寄存器 x16-x17 用作特殊用途寄存器。
   - 寄存器 x18 保留给全局数据指针使用(例如 TLS 模型)。
   - 寄存器 x19-x28 用作通用寄存器,可以用于存储数据和进行算术运算。
   - 寄存器 x29(FP,Frame Pointer)用作栈帧指针,指向当前函数的栈帧的起始位置。
   - 寄存器 x30(LR,Link Register)用于存储函数调用时的返回地址。

总体而言,x0-x30 寄存器在 ARM64 架构中用于存储数据、进行算术运算、传递函数参数、控制程序流程等。在函数调用过程中,这些寄存器的使用通过约定规则来进行管理,有助于提高运行效率和优化编译代码。开发者需要根据编程需求合理使用这些寄存器,并遵循相关规则来保证程序的正确性和性能。
  1. 栈帧:在函数调用过程中,通过栈帧(Stack Frame)来保存函数的局部变量、返回地址和其他调用相关信息。每个栈帧由保护区域(Saved Registers)和局部变量区域(Local Variables)组成。栈帧中包含了被调用函数的返回地址,在函数返回时会恢复到该地址继续执行。

  2. 栈回溯算法:栈回溯的实现通常使用递归算法或迭代算法。下面是一种迭代的栈回溯算法:

    • 在当前堆栈帧中获取当前函数的返回地址。
    • 根据地址和可执行文件的调试符号表信息,匹配到对应的函数名称和行号。
    • 打印或记录匹配到的函数名称和行号。
    • 对于从地址中解析的下一个返回地址,重复上述步骤,直到回溯到最顶层的函数或者到达设定的回溯层数。
  3. 符号表:符号表是一个映射关系,将函数名与对应的地址关联起来。在栈回溯过程中,通过符号表可以将地址解析为函数名和行号等调试信息。在 Linux 系统中,可以使用调试符号表文件(例如 ELF 文件)来获取符号表信息。

  需要注意的是,栈回溯的准确性和可读性受到符号表的影响。如果可执行文件没有包含调试符号信息,或者没有正确设置符号文件的路径,栈回溯可能只能提供地址而无法解析为函数名和行号。因此,在构建可执行文件时,建议开启调试符号信息的生成并妥善保存符号表文件。

三、参考阅读

ARM体系结构:https://zhuanlan.zhihu.com/p/577979125?utm_id=0
内核中dump_stack:https://www.cnblogs.com/pengdonglin137/p/11109427.html
dump_stack:https://blog.csdn.net/weixin_52849254/article/details/130559085

  dump_stack 函数是 Linux 内核中的一个调试函数,用于在内核代码中打印当前的函数调用堆栈信息。它用于诊断和调试内核中发生的问题,如内核崩溃或死锁等。

  dump_stack 函数的原型定义在 kernel/lib/dump_stack.c 头文件中:

void dump_stack(void);
	__dump_stack();
		dump_stack_print_info(KERN_DEFAULT);
		show_stack(NULL, NULL) //arch\arm64\kernel\traps.c

  通过调用 dump_stack 函数,可以在内核日志中输出当前的函数调用堆栈信息。这对于定位问题非常有用,特别是在内核崩溃时,您可以通过查看内核日志中的堆栈跟踪信息来确定哪些函数导致了问题。

  要在内核代码中使用 dump_stack 函数,只需在适当的位置调用它即可。例如,在驱动程序中遇到错误或异常情况时,可以在相应的错误处理路径中调用 dump_stack 函数,以便在内核日志中获取有关问题的更多信息。

注:推荐一本讲调试技巧的书《Debug Hacks中文版—深入调试的技术和工具》,非常nice!!!

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

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

相关文章

vue3中shallowReactive与shallowRef

shallowReactive与shallowRef shallowReactive: 只处理了对象内最外层属性的响应式(也就是浅响应式) shallowRef: 只处理了value的响应式, 不进行对象的reactive处理 总结: reactive与ref实现的是深度响应式, 而shallowReactive与shallowRef是浅响应式。 什么时候用浅响应…

JVM——垃圾回收器(Serial,SerialOld,ParNew,CMS,Parallel Scavenge,Parallel Old)

目录 1.垃圾回收器的组合关系1.年轻代-Serial垃圾回收器2.老年代-SerialOld垃圾回收器3.年轻代-ParNew垃圾回收器4.老年代- CMS(Concurrent Mark Sweep)垃圾回收器CMS执行步骤&#xff1a;CMS垃圾回收器存在的问题缺点&#xff1a;CMS垃圾回收器存在的问题 – 线程资源争抢问题…

【计算机网络笔记】ARP协议

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

论文解读:《数据增强:通过强化学习引导的条件生成进行文本数据扩充》

Title:<Data Boost: Text Data Augmentation Through Reinforcement Learning Guided Conditional Generation> 期刊&#xff1a;EMNLP &#xff08;顶级国际会议&#xff09; 作者 Ruibo Liu; Guangxuan Xu; Chenyan Jia; Weicheng Ma; Lili Wang; et al 出版日期 20…

利用STM32和蓝牙模块构建智能物联网设备的开发指南

智能物联网设备在现代生活中扮演着重要的角色&#xff0c;而STM32微控制器和蓝牙模块则为实现智能物联网设备提供了基础支持。本文将介绍如何使用STM32微控制器和蓝牙模块构建智能物联网设备的开发指南&#xff0c;包括硬件设计、蓝牙模块配置、传感器数据采集和云平台连接等关…

最新版小权云黑系统 骗子添加查询源码

小权云黑系统添加骗子&#xff0c;查询骗子&#xff0c;可添加团队后台方便审核用&#xff0c;在线反馈留言系统&#xff0c;前台提交骗子&#xff0c;后台需要审核才能过&#xff0c;后台使用光年UI界面&#xff0c;新增导航列表&#xff0c;可给网站添加导航友链&#xff0c;…

使用opencv将8位图像raw数据转成bmp文件的方法

作者&#xff1a;朱金灿 来源&#xff1a;clever101的专栏 为什么大多数人学不会人工智能编程&#xff1f;>>> 这里说的图像raw数据是只包含图像数据的缓存。主要使用了cv::imencode接口将 cv::Mat转化为图像缓存。 #include <opencv2/opencv.hpp>/* 生成一幅…

excel对号怎么打

对号无论是老师批改作业&#xff0c;还是在标注某些数据的时候都会用到&#xff0c;但这个符号在键盘上是没有的&#xff0c;那么excel对号怎么打出来呢&#xff0c;其实只要使用插入符号功能就可以了。 excel对号怎么打&#xff1a; 第一步&#xff0c;选中想要打出对号的单…

基于51单片机的超声波测距系统【程序+proteus仿真+参考论文+原理图+PCB等16个文件夹资料】

一、项目功能简介 整个设计系统由STC89C52单片机LCD1602显示模块声光报警模块存储模块超声波模块按键模块组成。 具体功能&#xff1a; 1、超声波测量距离&#xff0c;显示在LCD1602。 2、存储模块可以存储超声波报警值。 3、通过按键可设置报警值大小。 4、超声波报警距…

金蝶云星空表单插件传递参数到服务插件

文章目录 金蝶云星空表单插件传递参数到服务插件业务需求开发实现传递参数接收参数 金蝶云星空表单插件传递参数到服务插件 业务需求 操作售后单行反关闭时将当前选中行的序号传递到服务端&#xff0c;然后在服务端接收序列号&#xff0c;根据序列号处理相关逻辑。 开发实现…

obsidian官网下载太慢

obsidian真的很强大&#xff0c;速度快&#xff0c;丝滑&#xff0c;但是官网很慢 上百度网盘链接&#xff01; 链接&#xff1a;https://pan.baidu.com/s/1CWoNRuyhtezLTTJOfRf9Jg?pwdxopt 提取码&#xff1a;xopt

在OpenCV中基于深度学习的边缘检测

引言 如何在OpenCV中使用基于深度学习的边缘检测&#xff0c;它比目前流行的canny边缘检测器更精确。边缘检测在许多用例中是有用的&#xff0c;如视觉显著性检测&#xff0c;目标检测&#xff0c;跟踪和运动分析&#xff0c;结构从运动&#xff0c;3D重建&#xff0c;自动驾驶…

如何在Ubuntu系统上安装Redis

Redis的下载 Redis安装包分为windows版和Linux版当前示例中介绍的是Linux版本Linux的下载地址&#xff1a;Index of /releases/ (redis.io)本次下载的压缩包为&#xff1a;redis-6.2.14.tar.gzRedis的安装 将压缩包通过ssh远程工具上传到Linux服务器中解压压缩包 tar -zxvf red…

基于可微分渲染器的相机位置优化【PyTorch3D】

在这个教程中&#xff0c;我们将使用可微渲染学习给定参考图像的相机的 [x, y, z] 位置。 我们将首先使用相机的起始位置初始化渲染器。 然后&#xff0c;我们将使用它来生成图像&#xff0c;使用参考图像计算损失&#xff0c;最后通过整个管道进行反向传播以更新相机的位置。…

Web3.0时代:区块链DAPP将如何颠覆传统模式

小编介绍&#xff1a;10年专注商业模式设计及软件开发&#xff0c;擅长企业生态商业模式&#xff0c;商业零售会员增长裂变模式策划、商业闭环模式设计及方案落地&#xff1b;扶持10余个电商平台做到营收过千万&#xff0c;数百个平台达到百万会员&#xff0c;欢迎咨询。 随着…

6.Spring源码解析-loadBeanDefinitions(String location)

这里resourceLoader其实就是ClassPathXmlApplicationContext 1.ClassPathXmlApplicationContext 在上文中图例就能看出来 获取资源组可能存在多个bean.xml 循环单独加载资源组 创建一个编码资源并解析 获取当前正在加载的资源发现是空 创建了一个字节输入流&#xff0c…

竞赛选题 题目:基于大数据的用户画像分析系统 数据分析 开题

文章目录 1 前言2 用户画像分析概述2.1 用户画像构建的相关技术2.2 标签体系2.3 标签优先级 3 实站 - 百货商场用户画像描述与价值分析3.1 数据格式3.2 数据预处理3.3 会员年龄构成3.4 订单占比 消费画像3.5 季度偏好画像3.6 会员用户画像与特征3.6.1 构建会员用户业务特征标签…

cpu飙高问题,案例分析(二)——批处理数据过大引起的应用服务CPU飙高

上接cpu飙高问题&#xff0c;案例分析&#xff08;一&#xff09; 一、批处理数据过大引起的应用服务CPU飙高 1.1 问题场景 某定时任务job 收到cpu连续&#xff08;配置的时间是180s&#xff09;使用超过90%的报警; 1.2 问题定位 观察报警中的jvm监控&#xff0c;发现周期…

LeetCode(33)最小覆盖子串【滑动窗口】【困难】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 76. 最小覆盖子串 1.题目 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串&#xff0c;则返回空字符串 "" 。 注意&#xff1a; 对于 t 中重复字…

python爬虫实习找工作练习测试(以下内容仅供参考学习)

要求&#xff1a;获取下图指定网站的指定数据 空气质量状况报告-中国环境监测总站 输入&#xff1a;用户输入下载时间范围&#xff0c;格式为2022-10 输出&#xff1a;将更新时间在2022年10月1日到31日之间的文件下载到本地目录&#xff08;可配置&#xff09;&#xff0c;并…