一种面向多虚拟处理器的程序条件断点技术
2023-07-05戴丽虹武咏晗
王 洋,申 彪,彭 亮,戴丽虹,武咏晗
北京航天自动控制研究所,北京 100854
0 引言
嵌入式软件虚拟化仿真技术是通过模拟目标机嵌入式处理器及外设指令级行为,结合软件调试信息解析和使用技术,使得软件调试和测试摆脱对嵌入式目标硬件设备的依赖。
通过对航天控制领域虚拟化仿真和程序调试相关文献的检索,发现文献[1]基于SPARC的嵌入式处理器研究了操作系统的移植方法;文献[2]利用数据分发服务技术构建了数据通路,提出一种处理器之间的通讯解决方案;文献[3]探索了多核虚拟处理器不同核之间的通信方式,提供了一种快速的多核同步技术;与本文面向通用嵌入式处理器不同,文献[4]提出了一种针对PLC(可编程逻辑控制器)这类专用嵌入式软件的断点控制技术。
仿真技术和调试技术是现代软件调试的重要技术,通常目标文件代码段、数据段是仿真器的输入,目标文件代码段反汇编生成汇编指令序列,仿真模型完成汇编指令的取指、翻译、执行以及处理器外设的仿真。调试器以目标文件中调试信息段作为输入,通过解析和识别源代码中行信息、符号信息配合仿真器完成调试工作。
条件断点技术是软件调试技术的重要技术分支,通常应用于某一种处理器架构下的程序调试功能。与基于X86处理器和Windows操作系统API的程序断点技术不同[5],基于软件仿真技术的条件断点运行在嵌入式虚拟处理器上而非真实的处理器。如何实现面向不同编译器、嵌入式虚拟处理器的程序条件断点控制是一个重要的技术问题,本文提出的面向多虚拟处理器的程序条件断点技术支持多种编译器、多种嵌入式处理器架构,主要创新内容如下:
1)提出一种通用的调试信息存储结构;
2)提出一种条件断点控制技术;
3)提出一种通用架构条件断点控制模型;
4)基于通用条件断点控制模型开发调试器DIP并完成了功能测试。
1 一种通用的调试信息存储结构
1.1 问题提出
嵌入式软件目标文件格式的组合方式有多种,运行嵌入式软件的目标处理器架构也不同,例如CC编译器生成目标文件为COFF加DWARF组合,目标处理器为DPS架构、GCC编译器生成目标文件为ELF加STABS组合,目标处理器为SPARC架构、ARM某编译器采用ELF加DWARF组合,目标处理器为ARM架构。如何构建通用的仿真调试模型来兼容多种编译器和多种处理器,如何构建通用的条件断点模型,实现不同嵌入式软件深层次缺陷快速定位成为重要问题,为解决上述问题,本文提出了面向多虚拟处理器的程序条件断点技术。
1.2 DWARF和STABS调试信息结构
DWARF[6](Debug with Arbitrary Record Format)调试信息保存在目标文件原始信息数据结构中,该数据结构定义如表1所示。
表1 DWARF主要节区定义
DWARF以树状结构保存各个编译单元的序言数据、符号调试信息数据、行号调试信息数据。此时,全部调试信息是未经过重新组织的,编译单元、函数、局部变量、全局变量、数据类型的压缩信息分散在不同的数据结构中。
调试信息单元DIE(Debugging Information Entry)是符号结构信息(.debug_info)的基本单位,DIE中包括一个标签和多个属性,每个DIE节点与它的兄弟节点或子节点连接构成树形结构。假设在main.c中定义两个函数function1和function2,function1函数中定义了变量var1。则main.c具备编译单元标签以及名称属性、编译路径属性、目标码覆盖范围等属性,function1和function2是main.c的子节点且互为兄弟节点,function1和function2具备子程序标签以及函数名属性、函数起地址范围等属性。Var1作为function1的子节点具备变量标签、局部存储属性、变量名属性、变量位置等属性,因此不难发现main.c中的DIE构成具有2个兄弟节点的3级树形结构。
DIE中描述的函数、全局变量、局部变量等保存的位置可能在内存、堆栈、寄存器中。符号的位置信息(.debug_loc)保存函数的栈帧信息和全局变量的静态位置信息、局部变量的动态位置变化信息。
行号调试信息(.debug_line)构建了源代码行信息与目标码行信息的对应关系,当处理器运行至特点目标码时,用户可以根据上述对应关系,确定程序运行的源码行。
STABS[7](String Tables)调试信息中符号和行号调试信息是以条目化的数据项形式存在的,STABS分为符号和行号调试信息,分别用.stabs条目和.stabn条目表示。
.stabs条目包括string,type,desc和value字段,其中string表示符号名称(例如上文中main.c,function1,function2和var1),desc表示符号属性(例如全局、局部、静态等属性),value表示符号寻址方式和寻址内容(例如内存、堆栈偏移、寄存器等)。
.stabn条目包括type,desc,value和type表示行号类型标识,desc标识源代码行,value标识目标码地址或目标码地址序列的起始地址。
1.3 一种通用调试信息存储结构
本文提出了一种如图1所示的通用调试信息存储结构,该存储结构是一种与目标文件格式无关的结构。存储结构中一个源程序的全部调试信息存储在CModule对象中,CModule对象中实例化
一个CModuleInfo对象中保存一个编译单元全部调试信息,包括:
1)函数信息Map
2)局部变量Map
3)全局变量Map
4)行号信息Map
5)数据类型信息Map
6)当前编译单元的编号、名称、起始PC值和结束PC值。
CFunctionInfo对象包括函数名、函数起始PC值、函数结束PC值、函数名所在的源代码行、CSymbolX对象,该对象保存函数名对应的符号信息,包括:
1)符号名称;
2)符号的类型CTypeX*;
3)符号的寄存器偏移(局部变量寄存器存储);
4)符号的栈帧偏移(局部变量堆栈存储);
5)符号的物理地址(全局变量);
6)符号的存储类型(寄存器、堆栈、内存)。
CSymbolX*保存局部变量和全局变量的符号信息。CSymbolX对象中保存了当前变量的类型信息CTypeX*,CTypeX包括:
1)类型名称、编号;
2)类型的种类,包括基本类型和结构体、枚举等多种类型;
3)指向CTypeX*的对象,此对象非空则表示该类型为指向其他类型的typedef类型;
4)类型的属性,包括静态属性、寄存器存储、参数存储、全局存储、枚举成员、结构体;
5)成员、联合体成员、函数成员等;
6)复合类型如结构体中各个元素的索引系数,包括位索引和字节索引。
CSymbolX*的哈希表,用以保存当前类型下引用到得新的符号信息。
CLineInfo*保存行号调试信息,CLineInfo对象包括:
1)源代码行;
2)当前源代码行对应的目标码序列。
图1 通用的调试信息存储结构
2 程序条件断点控制技术
2.1 处理器虚拟仿真技术
嵌入式处理器仿真技术是在宿主机上模拟目标处理器行为,实现图2所示的嵌入式软件仿真,一般执行过程包括:
1)反汇编器对嵌入式程序的二进制目标文件的代码段进行反汇编,生成汇编指令码;
2)处理器仿真模型中PC控制逻辑取程序入口PC后,汇编指令执行器开始执行指令周期循环(取指、译码、执行);
3)仿存模型中保存程序执行过程中的静态内存、堆内存、栈空间和寄存器数据;
4)断点控制器注册处理器外部回调函数,回调函数处理条件断点事件。
图2 虚拟处理器仿真行为模型
2.2 条件断点控制技术
在虚拟处理器架构下,实现条件断点方式如图2中程序所示,假设条件断点的触发条件是structX.stFoo.iBar==5,触发位置为图3中第13行。实现条件断点的控制过程则如下:
首先,需要对表达式进行词法和语法分析。本文利用Flex&bsion构建语法树,语法树叶子节点为iBar,iBar的父节点为stFoo,stFoo的父节点为structX;
图3 条件断点程序伪代码
其次,通用的调试信息存储结构CSymbolX*中保存有structX.stFoo.iBar数据结构信息, CTypeX*保存有structX和stFoo的结构体类型信息,通过寻址解析逻辑可以获取iBar的地址;
最后,行号调试信息CLineInfo中存有语句structX.stFoo.iBar==i表达式所在图3所示的源码行(13行)和该语句对应目标码的PC,当处理器模型判断当前处理器的PC与structX.stFoo.iBar==i行所处PC相同时,断点控制器触发函数回调:
1)断点控制器通过iBar地址查询当前的iBar值,将iBar值传入回调函数;
2)回调函数判断iBar值是否等于5,如果等于5则处理器PC保持,程序暂停;如果不等于5则程序PC增加后继续运行。
2.3 通用条件断点控制模型
利用图4所示的条件断点控制技术,可以构建图5所示的通用条件断点控制模型,该模型包括4个主要部分:
图4 条件断点控制原理图
图5 通用条件断点控制模型
第1部分,调试信息解析逻辑和通用调试信息存储模型,调试信息解析逻辑支持对不同编译器的调试信息格式解析,解析格式包括ELF、COFF、Stab、DWARF-v2、DWARF-v3、DWARF-v4以及自定义的调试信息格式,通用调试信息存储模型中保存统一的调试信息,通用调试信息包含行号信息、符号信息[8]。
第2部分,模块化的虚拟处理器模型和通用的条件断点控制接口,通用的条件断点控制接口适配不同处理器,接口中统一处理来自FLEX&BISON注册的回调函数,处理过程如图6所示。
图6 调试器DIP架构图
第3部分,FLEX&BISON引擎,引擎具备3个主要功能:
1)FLEX&BISON引擎将条件断点表达式解析为符号树,符号树种全部变量的地址和类型等信息通过查询通用调试信息存储结构获取;
2)FLEX&BISON引擎解析条件表达式,以函数回调的形式,注册在通用断点控制接口中,满足断点表达式条件时,虚拟处理器暂停运行;
3)FLEX&BISON引擎收到虚拟处理器暂停运行消息后,通知前端调试器暂停在条件断点所在的源码行。
第4部分,前端调试器。前端调试器用于显示条件断点,显示当前调试的源代码等。
3 软件实现与验证
基于通用架构条件断点控制模型开发了调试DIP,软件实现架构如图6所示[9]。
调试器实现了对DWARF和STABS调试信息的解析,支持通用的调试信息存储格式,支持SPARC、DPS、ARM的处理器的仿真,支持前端用户界面,实现面向多编译器和多处理器的条件断点控制。
为了考核条件断点调试解析功能的正确性、多编译器和虚拟处理器兼容能力,在表2所示的硬件场景进行了测试。
表2 测试平台硬件指标
考核7项内容,设计功能测试用例1203个,详细考核情况如表3所示。
表3 条件断点支持情况
例如针对通用条件断点处理功能,如表4所示,测试用例考核了等于、大于、小于条件判断,考核结构体、联合体成员的符号判断逻辑,考核程序特定语句命中次数的判断逻辑,通过条件断点功能发现了多个载人航天型号控制系统嵌入式软件问题。
表4 通用条件断点处理逻辑支持情况
4 结论
随着航天领域嵌入式软件种类和复杂度增加,调试器从面向单一编译器发展为面向多编译器架构,为满足航天领域多种类型嵌入式软件的研发和测试需求,提出了一种通用的调试信息存储结构、一种条件断点控制技术和一种通用架构条件断点控制模型,基于通用架构条件断点控制模型开发了调试器DIP,将条件断点技术应用于载人航天、探月工程等多个核心关键嵌入式软件测试中。通过使用通用的条件断点功能,更容易发现不同嵌入式软件中的深层软件问题,在未来,以上技术将在更多航天型号嵌入式软件测试中得到验证和应用。