Embedded 版 (精华区)

发信人: lhwhit (lhwhit), 信区: Embedded_system
标  题: 嵌入式软件的远程调试
发信站: 哈工大紫丁香 (Fri Mar  8 11:04:33 2002) , 转信



嵌入式软件的远程调试
1  引言
调试是软件开发过程中必不可少的环节,通用的桌面操作系统与嵌入式操作系统在调试环
境上存在着明显的差别。在通用的桌面操作系统中,调试器与被调试的程序往往是运行在
同一台机器、相同的操作系统上的两个进程,调试进程通过操作系统专门提供的调用接口
控制、访问被调试进程,我们把这种调试方式称为本地调试。在嵌入式操作系统中,为了
向系统开发人员提供灵活、方便的调试界面,调试器仍运行于通用的桌面操作系统环境中
,被调试的程序则运行于基于特定硬件平台的嵌入式操作系统(即目标操作系统)环境中
,这种调试方式我们称之为远程调试。
远程调试系统由三部分组成:主机上的调试器,目标机上调试器和远程调试协议[1]。
由于远程调试与本地调试方式的不同,因而带来以下问题[2]:
·调试器与被调试程序如何通信?
·被调试程序产生异常如何及时通知调试器?
·调试器如何控制、访问被调试程序?
·调试器如何识别有关被调试程序的多任务信息并控制某一特定任务?
·调试器如何处理某些与目标硬件平台相关的信息(如目标平台的寄存器信息、机器代码
的反汇编等)。

2  远程调试方案
2.1  插桩(stub)
插桩是指在目标操作系统和调试器内分别加入某些功能模块,二者互通信息来进行调试。
上述问题可通过以下途径解决: 
(1)调试器与目标操作系统通过指定通信端口(串口、网卡、并口)遵循远程调试协议进
行通信。 
(2)目标操作系统的所有异常处理最终都要转向通信模块,告知调试器当前的异常号,调
试器据此向用户显示被调试程序产生了哪一类异常。 
(3)调试器控制、访问被调试程序:调试器的这类请求实际上都将转换成对被调试程序的
地址空间或目标平台的某些寄存器的访问,目标操作系统接收到这样的请求可以直接处理
。对于没有虚拟存储概念的简单的嵌入式操作系统而言,完成这些任务十分容易。 
(4)调试器识别有关被调试程序的多任务信息并控制某一特定任务:由目标操作系统提供
相关接口。目标系统根据调试器发送的关于多任务的请求,调用该接口提供相应信息或针
对某一特定任务进行控制,并返回信息给调试器。 
(5)调试器处理与目标硬件平台相关的信息:第(2)条所述调试器应能根据异常号识别
目标平台产生异常的类型也属于这一范畴,这类工作完全可以由调试器独立完成。支持多
种目标平台正是GNU GDB的一大特色。 
综上所述,这一方案需要目标操作系统提供支持远程调试协议的通信模块(包括简单的设
备驱动)和多任务调试接口,并改写异常处理的有关部分。另外目标操作系统还需要定义
一个设置断点的函数;因为有的硬件平台提供能产生特定调试陷阱异常(debug trap)的
断点指令以支持调试(如X86的INT 3),而另一些机器没有类似的指令,就用任意一条不
能被解释执行的非法(保留)指令代替。目标操作系统添加的这些模块统称为"插桩"(见
下图),驻留于ROM中则称为ROM monitor。通用操作系统也有具备这类模块的:编译运行
于Alpha、Sparc或PowerPC平台的Linux内核时若将kgdb开关打开,就相当于加入了插桩。

 
图1
运行于目标操作系统的被调试的应用程序要在入口处调用这个设置断点的函数以产生异常
,异常处理程序调用调试端口通信模块,等待主机(host)上的调试器发送信息。双方建
立连接后调试器便等待用户发出调试命令,目标系统等待调试器根据用户命令生成的指令
。这一过程如下图所示。
 
图2
这一方案的实质是用软件接管目标系统的全部异常处理(exception handler)及部分中断
处理,在其中插入调试端口通信模块,与主机的调试器交互。它只能在目标操作系统初始
化,特别是调试通信端口初始化完成后才起作用,所以一般只用于调试运行于目标操作系
统之上的应用程序,而不宜用来调试目标操作系统,特别是无法调试目标操作系统的启动
过程。而且由于它必然要占用目标平台的某个通信端口,该端口的通信程序就无法调试了
。最关键的是它必须改动目标操作系统。

2 .2  仿真器
远程调试的另一种方法是使用仿真器。微处理器仿真器是功能最强大的软件调试工具之一
。它用自己同样的微处理器替代目标系统的微处理器。仿真器使微处理器内部的寄存器完
全透明,并能提供自己的RAM或替代存储器去覆盖目标系统的ROM和RAM。为了在运行控制中
提供最大的灵活性。仿真器提供了软件和硬件断点。不需要任何系统资源,调试器和仿真器
之间的连接可在目标崩溃情况下生存,与插桩的方法相比,可用于后崩溃分析。对于多处理
器目标系统,可使用多台仿真器替代系统中的各微处理器。尽管看来似乎合乎理想,但仿真
器同样有一些明显的缺点。
仿真器第一个缺点是它的价格。随着处理器品种的增多和速度的提高,仿真器的价格在上扬
。对于最新的32bit处理器,相应的仿真器极其昂贵。另一个缺点是侵入性。尽管在仿真器
中使用的是非常接近于所替代的目标系统的微处理器,它仍然是具有不同电气特性的另一个
器件。作为这一差别的后果,仿真器把较大的负载加至系统总线,可改变系统时序。当仿真
器连到其它元件保持不变的目标系统时,有时会发生目标系统突然工作(或失效)的情况。随
着新处理器功能的增强,设计能够有效替代目标处理器的仿真器是极其困难的。许多新型处
理器中包括仿真器不可见的高速缓存。仿真器对能在1个时钟周期内执行多条指令的超标量
处理器的仿真能力存在问题。它难以跟上新型处理器的高速内部时钟速度。对现代RISC(精
简指令集计算机)处理器,内部时钟速率一般比总线速率高好几倍,可能超过100MHz。很难使
用在线仿真的传统方法对这样的处理器实现仿真。
仿真器另一项重要缺点是重复使用能力。只有在各项设计中一直使用同样的处理器,才不会
有问题。但处理器技术总是在前进。很可能下一项设计会使用与今天不同的处理器。它表
明要为现在所拥有的仿真器寻找其它用途。仿真器并不是通用的工具,只能在有限的处理器
范围内使用。

2.3 片上调试(On Chip Debugging)
嵌入式系统调试发展趋势是使用微处理器内的芯片上内置的仿真功能。IC制造商在芯片上
增加用于调试的电路,称为n线芯片上(n wire, on chip)调试,或后台模式调试(BDM Bac
kground Mode Debug)。这些特性使调试工具的开发能提供廉价的ROM监视器,以及具有稳定
硬件支持的基于仿真器的连接。这些方法可通过特定的一个或多个引脚访问处理器的调试
功能。与仿真器的仿真头不同,芯片上的调试器或n线调试器通常不需要涉及与全功能仿真
器连接相关的高速、严格的定时和负载问题。所提供的引脚在低价格的探头和微处理器间
以串行的方式传送信息。调试器使用n线探头作为与目标系统的接口,类似于使用仿真器或
ROM监视器的方法。在使用n线探头的情况下,调试器只需要提供运行控制、硬件断点、代
码下载和寄存器访问能力的几个信号。由于调试器和目标系统间通过硬件探头连接,不受目
标崩溃的影响,因而能很容易进行后崩溃分析。此外,对于具有n线调试的微处理器的多处
理器系统,对各处理器建立调试器连接也只要简单地连入适当数目的n线探头(每个处理器
一个)。因为调试功能被置入芯片内部,侵入性问题、处理器速度,甚至高速缓冲的可见性都
不再成为问题。
但芯片上调试也有它的限制。对于那些真正棘手的与硬件有关的软件故障,实时分析能力是
必不可少的。设计师们不能仅仅依靠微处理器总线来观察系统运行。在设计师寻找与微处
理器执行代码相关的系统事件时,实时分析必须结合系统分析进行[3]。

3  深入话题
传统的调试方法可概括为如下过程:设断点--程序暂停--观察程序状态--继续运行。被调
试的如果是实时系统,即使调试器支持批处理命令避免了用户输入命令、观察结果带来的
延迟,它与目标系统之间的通信也完全可能错过对目标平台外设信号的响应。于是,针对
某些调试器(如GDB)提供的监视点(trace point)这一特殊调试手段,目标方的插桩在
原有的基础上被改进,称为代理(agent)。调试时用户首先在调试器设置监视点,以源代
码表达式的形式指定感兴趣的对象名。为了减少代理解析表达式的工作,调试器将表达式
转换为简单的字节码,传送至代理。程序运行后命中监视点、唤醒代理,代理根据字节码
记录用户所需数据存入特定缓冲区(不仅仅是表达式的最终结果,还有中间结果),令程
序继续运行;这一步骤无需与调试器通信。当调试器再度得到控制时,就可以发出命令,
向代理查询历次监视记录。较之于插桩,代理增加了对接受到的字节码的分析模块,相应
的目标代码体积只有大约3K字节;当然,监视记录缓冲区也要占用目标平台的存储空间,
不过缓冲区的大小可在代理生成时由用户决定。总之,这一改进以有限的目标系统资源为
代价,为实时监视提供了一个低成本的可行方案。
调试并不仅仅意味着设断点--程序暂停--观察--继续这一过程,往往还需要profiling、跟
踪(trace)等多种手段,而现代微处理器的技术进步却为这些调试手段的实行带来了困难
。以跟踪为例,其目的无非是记录真实的程序运行流;可现代处理器指令缓存都集成于芯
片内(RISC处理器尤为如此),运行指令时"取指"这一操作大多在芯片内部针对指令缓存进
行,芯片外部总线上只能观察到多条指令的预取(prefetch),预取的指令并不一定执行
(由于跳转等原因);另外,指令往往经过动态调度后在流水线中乱序执行,如何再现其
原始顺序也是个问题。解决方案大致有以下三种: 
(1). 有的处理器除了正常运行外,还能以串行方式运行,所有的取指周期都可呈现于片外
总线(相当于禁用缓存与流水线)。这样一来,跟踪容易多了,处理器性能也大大降低了
,根本不适用于实时要求严格的系统。 
(2). 编译器自动在指定的分支及函数出入口插入对特定内存区域的写指令(与gprof等pr
ofiling工具采用的手段类似),它们都是不通过缓存而直接向内存写的,这就能反映于芯
片外总线从而被外接的逻辑分析仪记录,最终由主机端的调试工具分析并结合符号表重构
程序流。这种方法虽被广泛使用,但毕竟是干扰式的(intrusive),对系统性能也有影响
。 
(3). 像上文所述的片上调试那样,也有处理器在片内附加了跟踪电路,收集程序流运行时
的"不连贯"(discontinuities)信息(分支和异常处理的跳转目的及源地址等),压缩后
送至特定端口,再由逻辑分析仪捕获送至主机端调试工具重构程序流。该方案对系统性能
影响最小。 
总之,处理器厂家提供集成于片内的调试电路为高档嵌入式系统开发提供各种非干扰式的调
试手段早已是大势所趋。为了解决该领域标准化的需要,一些处理器厂家、工具开发公司和
仪器制造商于1998年组成了Nexus 5001 Forum,这是一个旨在为嵌入式控制应用产生和定义
嵌入式处理器调试接口标准的联合组织,以前的名称是Global Embedded Processor Debug
 Interface Standard Consortium(全球嵌入式处理器调试接口标准协会)。Nexus现在有
24个成员单位,包括创始成员Motorola、Infineon Technologies、日立、ETAS和HP等公司
。该组织首先处理的是汽车动力应用所需要的调试,现在已发展成为调试数据通信、无线
系统和其他实时嵌入式应用的通用接口。

参考文献
1.黄瑞芳,朱敏,张卫民  远程调试的设计与实现.计算机工程与应用,2001.1:125~128

2.熊竞  http://www.picketix.com/documents/tech/2001073001.htm
3.Rick Eads 嵌入式发展需要新的调试工具. 电子产品世界 1998.9



--

※ 来源:.哈工大紫丁香 http://bbs.hit.edu.cn [FROM: 172.16.7.208]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:2.417毫秒