二进制文件符号信息
Dwarf简介
在日常的开发工作中,程序员经常使用gdb工具来调试二进制编译文件,以定位和解决一些bug。但同时,很少会有人关注二进制文件中的调试信息从何而来,又是怎么保存和解读的呢?
其实调试信息的来源很简单,就是从编译后的文件来的。编译器从源文件中将大量的符号信息(包括变量名、变量类型、变量所在行号、函数名以及参数之类)按照特定的格式进行打包写入到编译后的文件中,然后使用调试器就能从二进制文件中获取并解析相应的符号信息。
调试信息保存的格式有多种,主要有stabs,coff,pe-coff以及dwarf等,目前天目全数字实时仿真软件SkyEye解析符号使用的dwarf格式,本文着重介绍此种格式。
Dwarf的全称为「Debugging With Attributed Record Formats」,目前已有dwarf1,dwarf2,dwarf3三个版本,可以支持源代码级调试。程序的dwarf描述结构是一种树形结构,采用xml格式解析,每个节点都可以有子节点或者兄弟节点。节点可能代表类型、变量或者函数。
Dwarf信息结构
Dwarf的信息结构是由多个section组成的,其中各个section内部又包含各个信息块,整体结构图如下所示:
▲图-1 Dwarf结构示意图
Dwarf主要包含的section以及相应的意义如下表:
▲表-1 section节以及内容
其中,绝大多数的调试信息都包含在.debug_info中,其内部又包含多个compile_unit(编译单元),编译单元来源于程序的每个单独编译的源文件,包含路径以及源文件名、使用的编程语言等信息,同时,每个编译单元还包含源文件中的全局符号信息的die信息块,主要分为「tag」和「attribute」两个信息块,其中「tag」表示数据类型信息,「attribute」表示其属性值,常见标签参考下表:
▲表-2 标签信息
解析dwarf数据信息
上述说明了dwarf格式是如何保存调试信息的,但一个符号信息可能有多种类型表示,比如,一个stru_data_test.int[0]这么一个全局变量,它又是结构体内部的元素,又是一个数组,如何准确地描述这种类型的变量信息呢,答案是通过「id_ref」这个属性将多个die信息块进行组合。
以stru_data_test.char1变量为例,实际解析过程如下所示:
▲图-2 结构体符号解析过程示意图
符号解析过程中,先是通过查找到id为「0x8:0x8667」的die信息块,获取到变量的变量名信息,但具体的变量类型通过idref查找到第二个信息块「0x8:0x864f」,通过获取第二个die的类型信息,关联到第三个信息块「0x8:0x84c0」,根据第三个die的类型是DW_TAG_structure_type,通过查找下级的元素die的信息,可以获得变量名为char1的元素,同时也可以根据属性DW_AT_data_member_location来获得变量在结构体内部的偏移值。如此便可以根据Dwarf的die信息将实际需要的符号信息进行解析。
天目全数字实时仿真软件SkyEye
SkyEye,中文全称天目全数字实时仿真软件,是基于可视化建模的硬件行为级仿真平台,支持用户通过拖拽的方式对硬件进行行为级别的仿真和建模。
SkyEye目前支持主流的嵌入式硬件平台,可以运行主流的操作系统,此外还能适配国内自主研发的操作系统天脉。通过利用基于LLVM的动态二进制翻译技术,使虚拟处理器在典型的桌面计算机上运行速度可以达到2000MIPS以上。
基于可视化图形的硬件建模,有效降低了硬件工程师和软件工程师之间的沟通成本。软件工程师可以不依赖于硬件工程师,而根据需要对硬件的配置进行改动。
在SkyEye中涵盖了ARM、PowerPC、 DSP、SPARC、x86、龙芯、飞腾等主流的嵌入式系统架构的仿真,可以应用于航空、航天等多种安全关键领域。