嵌入式系统那些事——aarch64 backtrace嵌入式汇编实现

news2024/10/3 4:36:07

0 背景

        在aarch64嵌入式应用开发中,经常会遇到段错误(segmentation fault),但是通常情况下系统报错后直接退出,没有异常调用打印信息,定位出错原因十分困难。经确认,该问题是由于没有设置捕获段错误,并调用backtrace打印异常调用栈,笔者实现该异常捕获处理方案后,发现仍然没有异常调用栈输出。经进一步定位发现,该嵌入式设备上使用的glibc库版本过低,并不支持aarch64的backtrace功能。

        笔者找到glibc的最新开源版本glibc2.36(2022年8月发布),其中包含了对aarch64 backtrace功能支持。面对这种情况,能想到的第一种解决方案是将glibc升级到最新的版本,但是这样除了要交叉编译glibc以外,所有的组件,包括操作系统和应用程序都要一起交叉编译更新,复杂度很大。还有一种解决的思路是,将其中backtrace相关的功能移植过来,通过实验发现,这个移植工作量同样很大。于是笔者萌生了基于backtrace的原理和嵌入式汇编自己去写一套aarch64上可以使用的接口。

1 backtrace实现原理

        backtrace的实现本质上是基于最基本的函数调用关系的回溯过程。在我们的代码中,函数是一级一级调用下去的,每个函数都有自己的母函数或者子函数,这种调用关系就像阶梯一样,形成一个调用栈,出现问题后,我们就可以从出现问题的函数起,恢复出调用它的整个函数过程,这样就可以知道是哪一段流程调用出现的问题。函数之间的调用关系是由系统维护的,作为程序员通常不需要关注,但是此处想模拟函数调用栈回溯的过程,就需要对这个函数调用栈的基本原理有所了解。

        如下图所示,展示了调用者和被调用者的关系。这个关系用栈来存储,我们知道栈最基本的原理是先进后出,这样就可以保证被调用者先执行返回结果给调用者。在函数调用栈的设计中,栈是由高地址往低地址增长的,这个在笔者前面的文章【1】有介绍,当调用关系发生时,调用者会首先被压入栈中,被调用者后被压入栈中。被调用者压入的同时,调用者的返回值地址和调用者下一条将要执行的指令地址会被存储在寄存器中,当被调用者执行完成后,就可以基于该返回地址回到调用者的栈顶,然后继续执行调用者的下一条指令。

        上图中,aarch64存储返回地址和下一条要执行的指令地址的寄存器分别是FR(X29)和LR(X30)。这两个寄存器可以通过反汇编aarch64编译出的bin文件得到,如下图所示,在汇编函数的头两行。需要注意的是不同的体系结构这两个寄存器是不一样的,如arm32就可能是另外的寄存器,需要根据实际情况,反汇编得到。如果想要验证这两个寄存器的值,可以在c代码中嵌入汇编语言,在函数开始的地方,打印出这两个寄存器的值,后续笔者就是通过这种方式找到函数之间的回溯规律的。

2 aarch64 backtrace代码实现

        以如下图最左侧所示的函数调用关系为例,图中函数的调用关系依次为:main=>func_a=>func_b=>func_c,假设在函数func_c中访问了空指针导致段错误,那如何恢复出整个异常函数调用栈呢?

        首先将系统默认的段错误直接退出应用程序改为通过捕获异常信号的方式接管。即捕获SIGSEGV异常信号,并注册回调处理函数为print_trace,在其中调用aarch64的这个红色标注的backtrace_arm,该核心代码我们稍后介绍,此处得到函数的异常调用栈为下一条执行的指令地址,而不是当前执行的函数的入口地址,感兴趣的读者可以在x86的虚拟机上实验glibc中的backtrace库函数,看一下是不是这样的规律。最后就可以直接使用backtrace_symbols库函数解析异常调用栈地址为对应的函数名。

        为了更深刻地理解函数异常调用栈的回溯原理,我们首先可以将x29和x30寄存器地址和存储的值打印出来。从上图中可以看到被调用者的fp(x29)存储的值是调用者的fp的地址,依次递归,直到fp的地址为0。如果将lr(x30)存储的值在反汇编的代码中搜索,刚好可以对应到被调用者返回后下一条要执行指令地址地址。有了这两个规律,我们就可以通过不断循环访问x29寄存器的值,直到0,回溯整个调用栈,如上图最右边所示;在回溯到每个调用者的时候,通过减去2就可以得到lr寄存器的地址,不需要直接去访问x30寄存器,此时访问的话也会出错,因为我们并没有真正去弹栈,而是模拟弹栈回溯。为何要减去2,就可以得到lr的地址?因为入栈的时候下一条将要执行的指令地址寄存器x30的值先被压入,而后返回地址寄存器x29的值才被压栈,根据栈是由高地址往低地址增长的,所以回溯的时候,地址要做减法。至于减去2,则是因为我们是aarch64的体系结构,一个地址需要两个32位的存储空间,上图打印的fp地址虽然显示32bits,实际上是64bits。,这里是很容易出错的。

        核心的嵌入式汇编代码实现如下图所示。代码实现的逻辑上文已经说明此处不再重复。需要注意的点是如果不熟悉访问寄存器的指令可以反汇编得到。下图中最后的buffer中存储每次栈回溯时的lr寄存器的值,即下一条将要执行的指令。

        最终的结果如下图所示,可以得到异常调用栈回溯的下一条指令组成的调用栈,最后输入到backtrace_symbols函数中,就可以转换出函数名。

3 小结

        本文带着读者从函数调用栈的原理入手,以自己实战的backtrace_arm为例,详述了整个实现过程。感兴趣的读者可以自己动手实验一下,相信有更大的收获。

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

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

相关文章

推荐3dMax三维设计十大插件

3dMax是一款功能非常强大的三维设计软件,但无论它的功能多么强大,也不可能包含所有三维方面的功能,这时候,第三方插件可以很好的弥补和增强3dMax的基本功能,下面就给大家介绍十款非常不错的3dMax插件。 森林包&#xf…

Unsupervised Question Answering 简单综述

Unsupervised Question Answering by Cloze Translation, ACL 2019 随机从文本中抽取noun phrases或者named entity作为答案将答案部分mask掉,生成cloze question利用无监督翻译,将cloze question转化为natural question 缺点: 直接利用原句…

Android 进阶——Framework核心 之Binder Native成员类详解(二)

文章大纲引言一、Native 家族核心成员关系图二、Native 家族核心成员源码概述1、IInterface1.1、DECLARE_META_INTERFACE 宏1.2、IMPLEMENT_META_INTERFACE(INTERFACE, NAME) 宏1.3、sp< IInterface > BnInterface< INTERFACE >::queryLocalInterface(const String…

微前端qiankun架构 (基于vue2实现)使用教程

工具使用版本 node --> 16vue/cli --> 5 创建文件 创建文件夹qiankun-test。 使用vue脚手架创建主应用main和子应用dev 主应用 安装 qiankun: yarn add qiankun 或者 npm i qiankun -S 使用qiankun&#xff1a; 在 utils 内创建 微应用文件夹 microApp,在该文件夹…

_Linux (线程池)

文章目录线程池概述&#xff1a;线程池示例&#xff1a;代码细节代码结果展示线程池概述&#xff1a; 一种线程使用模式。 线程过多会带来调度开销&#xff0c;进而影响缓存局部性和整体性能。而线程池维护着多个线程&#xff0c;等待着监督管理者分配可并发执行的任务。这避…

Linux下文档类型转PDF的总结

我的环境 centos8 先说思路:先把字体上传到服务器,然后更新字体库 ,代码里面配置字体地址。 如果导出的还是乱码,要么没字体,要么检查代码里面的路径。 目录 1.上传windows字体到linux 2.建立索引信息,更新字体缓存

【基于ChatGPT+Python】快速打造前后端分离的OpenAI人工智能聊天机器人

&#x1f680; ChatGPT是最近很热门的AI智能聊天机器人 &#x1f680; 用途方面相比于普通的聊天AI更加的广泛&#xff0c;甚至可以帮助你改BUG&#xff0c;写代码&#xff01;&#xff01;&#xff01; &#x1f680; 下面是使用pythonChatGPTVue实现的在线聊天机器人&#xf…

shell脚本免交互与expect

目录 Here Document 定义 格式 注意 例子 统计行数 修改密码​编辑 expect 定义 基本命令 实验 免交互ssh主机 Here Document 定义 使用I/O重定向的方式将命令列表提供给交互式程序 格式 命令<< 标记....标记 注意 标记可以使用任意的合法字符&#xf…

SpringBoot笔记【JavaEE】

SpringBoot概念、创建和运行 1.什么是SpringBoot&#xff1f;为什么学习SpringBoot&#xff1f; Spring Boot 就是 Spring 框架的脚⼿架&#xff0c;它就是为了快速开发 Spring 框架⽽诞⽣的。 2.Spring Boot优点 快速集成框架【提供启动添加依赖的功能】内容运行容器【无需…

从零开始,打造属于你的 ChatGPT 机器人!

大家好&#xff01;我是韩老师。不得不说&#xff0c;最近 OpenAI/ChatGPT 真的是太火了。前几天&#xff0c;微软宣布推出全新的 Bing 和 Edge&#xff0c;集成了 OpenAI/ChatGPT 相关的技术&#xff0c;带动股价大涨&#xff1a;微软市值一夜飙涨 5450 亿国内外各家大厂也是纷…

为什么神经网络做不了2次函数拟合,网上的都是骗人的吗?

环境&#xff1a;tensorflow2 kaggle 这几天突发奇想&#xff0c;用深度学习训练2次函数。先在网上找找相同的资料这方面资料太少了。大多数如下&#xff1a; 。 给我的感觉就是&#xff0c;用深度学习来做&#xff0c;真的很容易。 网上写出代码分析的比较少。但是也找到了…

云计算|OpenStack|社区版OpenStack安装部署文档(十二--- openstack的网络模型解析---Rocky版)

前言&#xff1a; https://zskjohn.blog.csdn.net/article/details/128846360 云计算|OpenStack|社区版OpenStack安装部署文档&#xff08;六 --- 网络服务neutron的安装部署---Rocky版&#xff09; &#xff08;######注&#xff1a;以上文章使用的是openstack的provider网…

【Vue3】电商网站吸顶功能

头部分类导航-吸顶功能 电商网站的首页内容会比较多&#xff0c;页面比较长&#xff0c;为了能让用户在滚动浏览内容的过程中都能够快速的切换到其它分类。需要分类导航一直可见&#xff0c;所以需要一个吸顶导航的效果。 目标:完成头部组件吸顶效果的实现 交互要求 滚动距离大…

计算机视觉 对比学习13篇经典论文、解读、代码

为了快速对 机器视觉中的对比学习有一个快速了解&#xff0c;或者后续复习&#xff0c;此处收录了 13篇经典论文、一些讲解地较好的博客和相应的Github代码&#xff0c;用不同颜色标记。 ​ 对比学习 13篇经典论文 论文代码和博客http://​www.webhub123.com/#/home/detail?p…

Nextjs了解内容

目录Next.jsnext.js的实现1&#xff0c;nextjs初始化2&#xff0c; 项目结构3&#xff0c; 数据注入getInitialPropsgetServerSidePropsgetStaticProps客户端注入3&#xff0c;CSS Modules4&#xff0c;layout组件5&#xff0c;文件式路由6&#xff0c;BFF层的文件式路由7&…

爬虫笔记之——selenium安装与使用(1)

爬虫笔记之——selenium安装与使用&#xff08;1&#xff09;一、安装环境1、下载Chrome浏览器驱动&#xff08;1&#xff09;查看Chrome版本&#xff08;2&#xff09;下载相匹配的Chrome驱动程序地址&#xff1a;https://chromedriver.storage.googleapis.com/index.html2、学…

vue83-103

vue全局路由拦截路由懒加载路由原理swiper组件选项卡封装电影导航组件正在热映获取数据渲染axios封装详情渲染详情轮播详情Header-组件影院组件渲染全局路由拦截 即使路径对&#xff0c;也会被拦截 router.beforeEach((to,from, next) > { console.log(to) if&#xff08;…

雅思经验(9)

写作&#xff1a;关于趋势的上升和下降在小作文中&#xff0c;真的是非常常见的&#xff0c;所以还是要积累一下。下面给出了很多词&#xff0c;但是在雅思写作中并不是词越丰富&#xff0c;分数就越高的。雅思写作强调的是准确性&#xff1a;在合适的地方用合适的词和句法。不…

【数据库】 数据库中表的基本操作

目录 表的基本操作 一&#xff0c; 创建表 1&#xff0c;单行命令创建表&#xff1a; 2&#xff0c;分行命令创建表&#xff1a; 二&#xff0c; 数据类型 1&#xff0c;文本类型&#xff1a; 2&#xff0c;数值类型&#xff1a; 3&#xff0c;日期/时间类型&#xff1a…

软件测试金融测试岗位,本人亲面

网上银行转账是怎么测的&#xff0c;设计一下测试用例。 回答思路&#xff1a; 宏观上可以从质量模型&#xff08;万能公式&#xff09;来考虑&#xff0c;重点需要测试转账的功能、性能与安全性。设计测试用例可以使用场景法为主&#xff0c;先列出转账的基本流和备选流。然…