物联网 (IoT) 设备呈指数级增长,这要归功于具有射频连接和微控制器内核的低成本集成片上系统设备的进步。
其中许多设备主要基于手臂®皮层®-M架构。随着硬件的进步,嵌入式软件在跟上新的连接协议、协议栈和框架方面发挥着重要作用。
然而,连接设备的激增给嵌入式软件工程师带来了挑战,尤其是同时在多个设备和框架上工作的应用和维护工程师。
了解新设备软件、框架和协议栈的工作原理可能非常耗时,并且会限制工程师快速解决问题的能力。设计文档和内联源代码注释可能会有所帮助,但它们可能不容易访问,并且可能无法提供代码工作原理的全貌。
在这些情况下,工程师依靠他们的独创性、足智多谋和使用集成开发环境 (IDE) 进行源代码浏览。虽然这在尝试理解软件代码流时有所帮助,但这是一个耗时且繁琐的过程,并且有更好的方法。
在本文中,我将介绍一种使用现有工具链实用程序生成软件的静态函数调用层次结构并更快更好地理解软件流的新颖方法。
函数调用跟踪的常见类型
可以使用函数调用跟踪来了解代码流或标识 Bug。比较成功和失败方案之间的程序流(通过函数调用跟踪)可以帮助您快速识别有问题的代码区域以进行进一步检查。
函数调用跟踪是对基于 IDE 的源代码浏览的补充,以更好地了解整个软件实现,并且可以分为两个常见类别:
运行时函数调用跟踪。这是一个侵入性过程,需要检测源代码。像GNU编译器集合这样的工具链提供了用于放置函数调用的检测,这需要重新构建代码以重新生成新的二进制文件,但会导致额外的代码大小和更长的执行时间。对于缺少内存的资源受限 IoT 设备,运行时函数调用跟踪可能不是一个可行的选项。此外,您无法保证检测的代码的行为与未检测的代码相同。
静态函数调用。对于基于只读存储器 (ROM) 的设备,检测不是一个可行的选择。虽然您可以简单地使用IDE(如Eclipse或源洞察)浏览源代码来了解软件实现,但这是一个繁琐的过程。一些IDE(通常是昂贵的商业版本)可以派生静态函数调用图。这些静态函数调用浏览器的范围通常有限,如果源代码中存在条件编译,则可能无法提供整个调用流的准确图像。
但是,可以从二进制可执行文件和可链接格式 (ELF) 文件生成静态调用流浏览器,该文件反映了实际的二进制代码。
使用静态呼叫流浏览器更快地修复软件
让我们使用设备的 ELF 二进制映像来生成函数调用引用详细信息。如图 1 所示,其思路是获取 ELF 二进制文件,并将其传递给各种代码生成工具,如 TI 的对象文件显示(armofd)和反汇编器(armdis),以生成函数列表和调用引用数据库。生成数据库后,在简单的树浏览器中显示调用层次结构和流,以查看函数调用引用。这些静态调用流程图还可以通过将运行时 ROM 代码消息日志叠加在静态函数树的顶部来帮助进行调试,这种组合将提供对运行时代码流的深入了解并帮助您隔离问题。
图1:ELF文件格式
二进制文件 (ELF) 分析
ELF 文件包含程序标头、节标头以及代码和数据节。工具链提供了各种工具,用于以可读的格式检查和显示 ELF 二进制文件内容。在 TI,我们使用 armofd 和 armdis 等实用程序名称来获取功能详细信息,并在 Arm 反汇编中完成程序编码。
图2:静态函数分析的过程
解析引擎遍历反汇编代码,并通过带有链接 (BL) 的分支和具有链接和交换 (BLX) 指令的分支检查函数调用,查找每个函数的所有调用函数,并填充函数数据库。数据库本身被安排为一个阿德尔森-维尔斯基和兰迪斯自平衡搜索树,用于快速搜索和浏览。
编译器优化可能会通过直接分支到被调用的函数来扭曲某些函数调用。这些函数没有任何堆栈分配,因此解析引擎需要足够智能才能检测到这些编译器优化。
功能浏览器
一个名为 Java 框架 (JFrames) 的简单图形用户界面 (GUI) 界面为函数调用浏览选择感兴趣的函数。选择一个函数将显示两个帧,一个用于“被调用方/被调用函数”,另一个用于“从调用自”函数。这些帧显示具有进一步节点扩展的分层树结构,如图 3、4、5 和 6 所示。
浏览器界面
函数列表显示所有可用函数,使您能够选择感兴趣的函数来浏览引用。
图3:功能列表显示
可以在树中进一步向下导航,以查看函数调用的可能性。
图 4:调用的函数引用
图 5:从引用调用
图 6:函数列表 GUI
简化软件
通过使用此方法从二进制图像派生静态调用流程图,您现在可以更好地了解软件功能流,并补充源代码浏览,从而更深入地了解软件实现。最重要的是,这种方法可以加快流程,使故障排除软件更简单。
审核编辑:郭婷
-
嵌入式
+关注
关注
5064文章
18994浏览量
302601 -
物联网
+关注
关注
2902文章
44179浏览量
370738
发布评论请先 登录
相关推荐
评论