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