新闻中心

EEPW首页>嵌入式系统>设计应用> 基于ELF的嵌入式软件源码级交叉调试技术

基于ELF的嵌入式软件源码级交叉调试技术

作者: 时间:2012-03-20 来源:网络 收藏

2、程序头表与段

程序头表中有多个表项,每个表项是一个程序段的信息,固定长度为32个字节,包含8个值,包括段在文件中的位置,段在内存中的起始虚拟地址,段的长度及其它属性等。调试器根据程序头表中的信息来确定需要下载到目标机上的目标文件内容(指令与数据)及其在目标机中的内存地址。

3、节头表与节

节头表中也有多个表项,每个表项是一个节的信息,固定长度为40个字节,包含10个值,包括节名、节的类型、该节在文件中的位置、该节在内存中的起始地址(如果该节出现在内存映象中)、节的长度等信息。某些节是程序段的组成部分,如包含程序二进制指令代码的正文节.text和数据节.rodata,.hash等,某些节不作为段的组成部分,只提供其它的额外信息。为源码调试服务的有 .debug,.line,.symtab,.debug_ pubname,.debug_range等节,其中.debug, .line节包含了源码调试信息的基本内容。

debug节中有多种类型的记录,可分为几大类:

编译模块信息:包含组成该文件的各个模块的源文件名,路径,及该模块的代码地址范围等。

子程序信息:包含程序名,程序类型,起始终止地址,程序返回结果存放地址等。

变量信息:包含变量名、变量类型、变量存放地址信息等,变量有多种类型,简单变量、结构变量等类型的变量其信息内容各有不同。

将.debug节中各项内容的结构关系抽象为家族关系。以节的起始为根,首先是一个编译单元的信息,它给出下一个编译单元(兄弟关系)在文件中的相对位置。紧跟着编译单元的是该编译单元中的子程序与公共变量信息(父子关系),同样的,编译单元中头一个函数记录或变量记录将给出它的兄弟的位置信息。紧随该函数记录的是该函数内部的子程序与局部变量信息。相邻层次成员是父子关系,同一层次上的成员是兄弟关系,如图4所示:

.line节中包含目标代码地址与源代码行号之间的对应关系。对每个编译单元给出其行记录信息的长度和目标码的起始基地址,以及该编译单元中所有的行记录,每条记录以固定的格式表示:“该行目标码相对于基地址的偏移,列号(保留,暂未使用),行号”。

综合上述程序段和节的内容,即可确定源码与目标码的映射关系。如给定一个文件名及行号,确定其目标代码的信息。首先根据文件名确定其在.debug 节中的编译模块信息,从中可得该文件模块的起始终止地址;再由其起始地址找到该编译模块的行记录信息在.line节中的位置,根据行号找到行记录,得到该行目标码的地址范围;由这些地址信息,可直接从目标机内存中取得目标代码,也可结合程序段信息从目标文件的程序段中取得该行所对应的目标代码指令内容。调试器利用地址与指令信息就可以查看、修改、执行相应目标代码,供用户进行调试。

4 源码级交叉调试器实现的技术要点

在设计交叉调试器JDBG时,首先完成与目标文件无关的部分:连接目标机,查看修改目标机寄存器和内存;然后实现与目标文件有关的部分:下载目标文件到目标机,源码级调试功能,包括断点控制、执行控制、变量观察等,以下重点讨论各项功能的设计与实现。

1、下载目标文件

目标文件中包含多种类型的内容,目标程序在目标机上运行时只需要程序的二进制指令代码与相关数据,这些内容包含在文件中的可执行程序段中。下载目标文件时在宿主机上提取目标文件中的代码与数据段,根据其地址映射关系利用remote协议中写内存的功能在目标机上建立程序的远程映像。

2、断点

断点是调试器控制程序执行的基本手段。各种机器有其特殊的断点指令(如X86的int3指令),设置断点就是将机器断点指令替换所指定程序单元中的指令,使得程序运行到断点指令处时,产生“断点异常”,用户程序不再继续执行下去,目标机向宿主机返回断点停止信号,由宿主机调试器接管对用户程序的控制。

断点分为逻辑断点与物理断点,两者是多对一的关系。逻辑断点与源代码对应,提供源级断点信息(源文件名+行号或物理地址等);物理断点与目标码对应,提供断点的目标码地址及断点处的指令内容。插入一个断点即根据逻辑断点信息确定物理断点地址,将该地址对应指令用机器断点指令替代;删除断点即恢复断点指令处预先保存的原指令,使得程序可继续执行。

检查点是一种条件断点,使程序在条件满足时停止执行。通常条件都涉及表达式的值变化,利用写内存保护来检查表达式的值是最常用的方法,但这种方法不适用于不具备MMU功能的处理器。某些处理器(如i386)提供了专门的调试控制寄存器,通过在调试控制寄存器中设置相应线性地址及中止条件(读或写)即可中止程序的运行。通过查询方式检查表达式的值也是一种可行的方法,其效率相对较低。当检查点的条件满足时,检查点的操作与普通断点类似。

对一个断点应具有基本的插入、删除、使能、使不能等基本操作功能。在设计中采用双向链表结构作为断点的数据结构,使得断点控制更加方便高效。

3、启动程序运行

启动程序运行首先从目标文件的ELF头中得到应用程序的入口,将目标机的PC寄存器置为该入口地址,从入口处开始执行程序指令。如果程序中没有设置任何断点或检查点,则程序一直运行到结束;如果程序中有断点,则程序运行到第一个断点处停止并返回其停止位置。

4、源码级单步调试

源码级单步以行为单位,一行源代码对应多条机器指令,因此一个源语句的单步执行需要多个机器指令的单步执行。最简单的实现方法就是从源语句对应目标代码的起始地址开始逐条单步执行机器指令。显然这种方法效率很低,尤其调试嵌入式软件需要大量宿主机/目标机间的通讯,而且有的处理器自身并不提供机器单步执行指令。因此,更有效的方法是用“内部临时断点+连续执行”的方式来实现。



评论


技术专区

关闭