关键词:
嵌入式跟踪调试(精选三篇)
嵌入式跟踪调试 篇1
随着嵌入式应用的深入和发展,特别是在数字通信领域的应用,对嵌入式跟踪调试软件运行效率和性能的要求在逐步提高,故在系统运行速度快、实时性要求高的嵌入式系统中,如何利用跟踪调试技术实现对芯片内部和整个ARM子系统的测试与监控成为了ARM调试技术的难点。而不断增长的处理器频率也给实时跟踪分析带来了一个又一个挑战,所以嵌入式跟踪调试技术的重要性推动着新技术的持续发展,使得跟踪分析工具也在不断创新[1]。
由于跟踪调试技术需要很高的可靠性、实时性,而在LTE系统中还要保证能够满足高速的数据业务传输,这成为在LTE系统中实现跟踪调试技术的矛盾点。本文提出了既能使跟踪调试软件高效地在LTE系统中运行,又能保证不影响LTE系统的高速率数据业务传输的跟踪调试技术方案。
1 方案设计需求
本方案的设计总体要求是既要使跟踪信息按照预想的方式输出,保证跟踪信息的可靠性、完整性和正确性,便于工程人员对异常情况的定位分析和流程控制,又要使整个ARM子系统消耗的资源小,即保证ARMcore处理器资源、总线压力和DDR访问最小[2]。首先,为了方便各种跟踪信息的封装和PC端解码软件的分析,需要对每条跟踪信息按照约定的格式进行封装和解析,这样才能保证跟踪信息的可靠性。其次,输出的跟踪信息应完整、实时地输出,有助于产品的开发和定位,保证跟踪信息的解析完整性和连续性,且在系统任务频繁切换时,保证信息不丢失且没有历史信息重复的显示。最后,从封装到PC端的解码软件解析之间有一条传输的物理通道(串口或USB),在硬件上需要保证传输跟踪数据在传输过程中的正确性。而在整个LTE系统中需要跟踪的信息种类繁多,需要对各种跟踪进行分类,以便在开发过程中对跟踪进行管理与配置,故将跟踪内容根据其特性分为常规性跟踪数据和临时性跟踪数据。常规性跟踪数据是指生命周期在方案设计、开发、调试测试、系统测试产品发布阶段;临时性跟踪数据是指生命周期在调试测试和系统测试阶段,如图1所示。
ARM基带系统的涉及面广,不同的工程类人员关注的跟踪信息种类不同,因此还需要对跟踪数据进行分类控制,以便使不同的工程人员关注各自相关的跟踪信息,要求本跟踪调试技术采用的控制方式是对跟踪源屏蔽的方式进行控制,可以保证整个系统效率[3]。
2 调试方法及功能介绍
嵌入式系统在开发过程中需要对软件进行调试,目前主要的嵌入式系统软件调试方法有两种。一种是在线调试(简称JATG Debug)[4],在线调试的主要手段是通过设置断点的方式来观察系统状态,从而找出软件设计中存在的问题。在线调试可以通过调试器观测到系统当前代码执行情况、内存数据、中断状态、硬件状态等信息和运行时调试信息进行问题分析定位。另一种调试方法是跟踪调试,预先在软件程序中插入跟踪点,在跟踪点调用跟踪模块获取跟踪点执行时刻的系统状态信息,可以监测系统变量、内存、状态机、函数执行情况、任务调度情况等内容。跟踪调试的方法不需要打断系统的运行,可以对系统顺序执行的状态变迁信息进行检测,因而在实时嵌入式系统的软件调试中应用非常广泛。
由于在线调试存在一些问题:在调试对时序严格要求的系统软件时,若断点观察系统状态,则系统无法再按正常时序运行;同时,在线调试无法监测到系统顺序执行的状态变迁,只能观察到某一时刻点的系统状态。所以本方案中采用的是第二种调试方法——跟踪调试。本方案中跟踪调试技术的主要功能是采集基带系统中的跟踪数据,通过UART/USB接口发送到PC端,并由PC端的跟踪软件进行解码显示。在跟踪调试技术中,提供一系列的跟踪接口,开发人员通过调用这些接口,将程序运行时的变量、内存数据和接口消息等输出到PC机上,再经过跟踪软件解析、显示。
3 跟踪调试方案的实现
跟踪调试的过程实际上就是任务先调用跟踪模块的跟踪接口开始跟踪,并为本次任务的跟踪信息分配缓存区,然后按照约定的信息格式对当前任务的跟踪信息进行封装,并将跟踪信息写入已分配好的缓存中,最后根据情况适时发送缓存中的跟踪信息,并在PC端的解码软件显示出需要打印的跟踪信息。基于以上机制,将跟踪调试模块的实现分为4个部分,如图2所示。
3.1 跟踪缓存的管理
ARM系统中各个模块调用跟踪接口时,需要将所有打印的跟踪信息缓存起来,再跟踪信息进行传输。故对于跟踪信息缓存的管理在整个设计中起着至关重要的作用[5]。
为了保证嵌入式系统的高效运行,保证ARMcore处理器资源、总线压力和内存访问最小,在片内RAM中专门为存储跟踪信息开辟了32 kbyte的循环缓存。而在嵌入式操作系统中又存在高低优先级任务间的切换,这样就存在高优先级任务的跟踪抢占低优先级任务的跟踪的情况,出现跟踪缓存竞争,故本设计采用的存储机制是在存储每条跟踪信息之前先为本条跟踪信息预留相应大小的存储空间,当低优先级任务的跟踪信息被高优先级任务跟踪信息抢占时,内存中已经为低优先级任务的跟踪信息预留了存储空间,从而不会导致跟踪信息的丢失和错乱的情况,如图3所示。
该方案的跟踪缓存机制主要思想是,利用所有跟踪函数在进入跟踪时均能够确切知道当前跟踪信息所需要的存储空间长度,从而为当前跟踪信息预留出所需要的存储空间。因此在跟踪函数入口处就对写指针进行偏移,在被高优先级任务抢占时,高优先级任务也不会再将跟踪数据写入其预留空间中,当高优先级任务执行完毕后,系统会自动回到低优先级任务执行,完成低优先级任务的跟踪信息的存储过程。
由于本设计中采用的缓存机制为循环缓存,故通过维护2个写索引和1个全局读索引来管理缓存,其中2个写索引分别为全局写索引和当前写索引,全局写索引用来与全局读索引进行匹配,通过这2个索引来计算缓存的剩余空间和已用空间,从而判断何时发送和写入跟踪信息,而当前写索引的作用就是为当前的跟踪信息预留空间。在对循环缓存管理时,发现向循环缓存中写入数据时,会出现跟踪信息的缓存超出32 kbyte的RAM空间(缓存超界)的现象。对于这种情况,设计一个带有保护机制的循环缓存,如图4所示,当数据超界时,将超界部分的数据写入保护区内,待数据写入完毕后,再将数据回拷到循环缓存的首地址处。
3.2 跟踪数据的传输
跟踪缓存数据的传输通道分为UART传输模式和USB传输模式。UART传输模式采用DMA总线完成中断的方式,在每次进入跟踪数据发送单元时配置DMA,本设计采用普通传输方式,第一次不需要等待中断,强制传输一次,目的地址固定不变,源地址递增,传输完成后更新全局读索引。由于在外场测试或没有条件进行串口跟踪时,需要通过USB来传输跟踪消息。USB传输模式直接调用USB跟踪数据传输接口进行跟踪数据传输,传输完成后更新全局读索引,如图5所示。
3.3 跟踪配置信息的管理
跟踪配置信息管理根据高层下发的配置信息设置跟踪数据类型控制变量。控制内容包括跟踪数据种类、跟踪数据长度、跟踪源的跟踪使能。通过跟踪类型设置位来控制应该打印某一类型的哪个或哪些消息。当外部模块调用跟踪函数时,会传递一个BIT值和一段字符串,这个时候需要用这个BIT值来和跟踪类型设置位进行比较,如果对应BIT位为1,则对应类型的跟踪数据需要输出,添加完成将跟踪信息通过DMA发送到串口的FIFO寄存器中,然后硬件打印跟踪信息,反之则不输出。
3.4 跟踪接口设计流程
该方案整个接口设计流程的关键在于怎样保证高低优先级任务的跟踪信息有序无误地存储到缓存,其设计流程如下:在函数入口处首先计算出当前跟踪信息的长度,将当前写索引保存到局部变量中,然后当前写索引偏移当前跟踪信息的长度,最后进行数据的封装和发送。由于嵌入式操作系统存在高低优先级任务之间的切换,故在每个接口进行此过程时,都有可能被高优先级任务抢占,因此设计了一个全局变量来记录被打断的次数(嵌套次数),每次函数入口该嵌套次数都会自加,函数出口嵌套次数再自减,若当前跟踪没有被抢占,则嵌套次数为0,若有被抢占的情况出现,则嵌套次数不为0,不更新全局写索引的值,故可发送的数据就不增加,只有每层的嵌套信息全部写入完毕后,嵌套次数才会减为0,才会将当前写索引的值赋值给全局写索引,这时全局写索引的值才会改变,可发送的数据才会增加。具体流程如图6所示。
4 方案及测试结果分析
本次跟踪方案从3个方面提高了ARM执行效率:1)在跟踪接口内部摒弃了svnprintf函数,直接将跟踪数据复制到跟踪缓存中,一方面把原方案中跟踪数据的原始码流通过svnprintf函数在ARM内部进行字符串的转化过程,转移到通过PC端的解码软件来解析原始码流而转化成可见字符串,另一方面摒弃svnprintf,也省去了函数遍历参数的过程(该过程消耗了ARM的执行时间),从变参的跟踪接口优化成定参接口,这种方式大大提高了ARM的执行效率;2)跟踪控制的优化,采用跟踪接口外部控制,若当前跟踪不需要打印时,则当前任务不会进入跟踪接口,直接丢弃本条跟踪,这样避免了函数的上下文切换的过程,减少了任务栈的切换从而提高了执行效率;3)缓存的优化,如本文所阐述,采用为跟踪预留空间的方式缓存,提高了跟踪信息的有序性。图7所示是通过调用几个相同的跟踪接口,来统计本条跟踪所消耗的LTE中1个子帧的时间片来统计时间,采用svnprintf时,调用跟踪接口消耗的时间为(0x4FB1-0x3DD8)×(1/0x7800) ms=0.147 8 ms。本方案中,跟踪接口消耗的时间为(0x3DC5-0x362D)×(1/0x7800)=0.063 3 ms。通过多次统计验证、测试并对比后发现本方案对ARM的执行时间提高了一半左右。在跟踪模块中减少了ARM的执行时间,从而使LTE系统中的其他模块有充分的时间来利用ARM资源,更好地达到LTE系统所要求的速率。
在提高效率的同时也要保证跟踪正确并可读,故在TTCN下进行各种场景的构造,包括高优先级任务的跟踪信息抢占低优先级任务的跟踪信息等,进行不断的调试测试,最终通过PC端的解码软件观察,跟踪出来的跟踪信息既没有重复显示历史跟踪信息,也没有出现跟踪信息丢失和错乱的情况,而是有序、准确无误地输出预想的跟踪信息,保证了本文开始所提到的可靠性、完整性和正确性。如图8所示,每条跟踪信息和跟踪变量的值都按照预想的方式输出。例如,灰底区域中的第1条用于调试测试阶段的临时信息为“ts_00_tra01_01dynamicTrace04,VRA1,VRA2,VRA3,VRA4”。但将整个LTE系统在中兴基站进行外场测试时,会出现跟踪信息多条丢失的情况,而对于开发人员来说,并不影响其流程控制和异常情况的定位分析,而且能够保证LTE系统50 Mbit/s的下载速率。
5 小结
随着多核产品的日益普及,跟踪调试系统解决方案要求的性能也愈来愈高,ARM公司针对复杂片上系统(SoC)设计推出了高度可配置的跟踪调试解决方案ARM CoreSightSoC,它满足了软件开发人员在SoC设计方面需要更高的可视性要求。而本方案的设计在满足开发人员高可视性需求的同时,既能高效地运行本跟踪调试软件,保证跟踪信息的正确性和完整性,又不会影响整个LTE系统高速率的数据业务,提高分析解决问题的效率。实现过程中通过不断的改进与调试,实现了在跟踪调试软件正常的运行下,LTE系统仍然能够在高速率下进行数据业务的传输。该方案的设计帮助了开发设计人员提高生产效率并缩短新产品上市的时间。
参考文献
[1]张欣,栾新.基于ARM芯片的嵌入式交叉调试系统[J].微计算机信息,2007,23(10):128-130.
[2]MARTIN A,FLAKE J.嵌入式系统软件调试跟踪技术的发展趋势[J].电子设计应用,2005(7):16-18.
[3]HU Xiao,CHEN Shuming.Applications of on-chip trace on debuggingembedded processor[C]//Proc.Eighth ACIS International Conference onSoftware Engineering,Artificial Intelligence,Networking,and Parallel/Distributed Computing.[S.l]:IEEE Press,2007:140-145.
[4]杜春雷.ARM体系结构与编程[M].北京:清华大学出版社,2003.
嵌入式跟踪调试 篇2
摘要:针对32位ARM处理器开发过程中调试技术的研究,分析了目前比较流行的基于JTAG的实时调试技术,介绍了正在发展的嵌入式调试标准,并展望期趋势。关键词:嵌入式调试处理器JTAGNexusARM
随着对高处理能力、实时多任务、网络通信、超低功耗需求的增长,传统8位机已远远满足不了新产品的要求,高端嵌入式处理器已经进入了国内开发人员的视野,并在国内得到了普遍的重视和应用。ARM内核系列处理器是由英国ARM公司开发授权给其他芯片生产商进行生产的系统级芯片。目前在嵌入式32位处理器市场中已经达到70%的份额。笔者在对三星公司的ARM7芯片技术调试的过程中,对这些高端嵌入式系统的调试技术进行了总结。
传统的调试工具及方法存在过分依赖芯片引脚、不能在处理器高速运行下正常工作、占用系统资源且不能实时跟踪和硬件断点、价格过于昂贵等弊端。目前嵌入式高端处理器的使用渐趋普及。这些处理器常常运行在100MHz,并且一些内部控制以及内部存储器的总线信号并不体现在外部引脚上。这种片上系统(SystemonChip)、深度嵌入、软件复杂的发展趋势给传统的调试工具带来了极大的挑战,也给嵌入式处理器开发工程师的工作带来了不便,这就需要更先进的调试技术和工具进行配套。本文将详细介绍在ARM处理器中采用的几种片上调试技术(on-chipdebugger)。这些片上调试技术通过在芯片的硬件逻辑中加入调试模块,从而能够降低成本,实现传统的在线仿真器和逻辑分析仪器的功能,并在一定的条件下实现实时跟踪和分析,进行软件代码的优化。
1边界扫描技术(JTAG)
边界扫描技术是为了满足当今深度嵌入式系统调试的需要而被IEEE1149.1标准所采纳,全称是标准测试访问接口与边界扫描结构(StandardTestAccessPortandBoundaryScanArchitecture)。JTAG遵循1149.1标准,是面向用户的测试接口,是ARM处理器调试的基础。本文提到的ARM的E-TRACE调试模式实际上是JTAG的增强版本,其它一些32位嵌入式处理器的调试方式也基本上遵循这个标准。这个用户接口一般由4个引脚组成:测试数据输入(TDI)、测试数据输出(TDO)、测试时钟(TCK)、测试模式选择引脚(TMS),有的还加了一个异步测试复位引脚(TRST)。其体系结构如图1。
所谓边界扫描就是将芯片内部内科所有的引脚通过边界扫描单元(BSC)串接起来,从JTAG的TDI引入,TDO引出。芯片内的边界扫描链由许多的BSC组成,通过这些扫描单元,可以实现许多在线仿真器的功能。根据1149.1的规定,芯片内的.片上调试逻辑通常包括一个测试访问接口控制器(TAP)。它是一个16状态的有限状态机以及测试指令寄存器、数据寄存器、旁路寄存器和芯片标识寄存器等。在正常模式下,这些测试单元(BSC)是不可见的。一旦进入调试状态,调试指令和数据从TDI进入,沿着测试链通过测试单元送到芯片的各个引脚和测试寄存器中,通过不同的测试指令来完成不同的测试功能。包括用于测试外部电气连接和外围芯片功能的外部模式以及用于芯片内部功能测试(对芯片生产商)的内部模式,还可以访问和修改CPU寄存器和存储器,设置软件断点,单步执行,下载程序等。其优点如下:
・可以通过边界扫描操作测试整个板的电气连接,特点为表面贴元件提供方便;
・各个引脚信号的采样,并可强制引脚输出用以测试外围芯片;
・可以软件下载、执行、调试和控制,为复杂的实时跟踪调试提供路径;
・可以进行多内核和多处理器的板级和芯片级的调试,通过串接(如图2),为芯片制造商提供芯片生产、测试的途径。
虽然JTAG调试不占用系统资源,能够调试没有外部总线的芯片,代价也非常小;但是由于JTAG是通过串口依次传递数据,速度比较慢,只能进行软件断点级别的调试,自身还不能完成实时跟踪和多种事件触发等复杂调试功能。因此便有了几种功能更为完善的增强版本。
2ARM芯片的实时调试方案(E-TRACE)
ARM公司的内核芯片采用E-TRACE片上调试模式。它实际上是JTAG的升级版本,通过增强的辅助片上调试硬件来完成实时调试,解决了许多传统调试器难以解决的问题。
图2对多内核和多处理器的调试
它的实时调试方案通过三种途径解决:
・EmbeddedICE硬逻辑;
・实时监控;
・实时跟踪。
EmbeddedICE逻辑单元存在于ARM7TDMI、ARM9TDMI、ARM9E和ARM10内核中。它枯JTAG口的基础上,增加了硬件断点寄存器、比较器,通过断点寄存器的值可以进行硬件断点的设置,
不仅对地址还可以对数据、控制总线的信号进行复杂的触发控制设定,而不是单单在指令级别进行中断(如软中断),从而满足对特定事件的中断响应,极大的增加了灵活性,同时可以在ROM中设置断点和观察点,极大地方便调试。其示意如图3。
实时监控则是进一步在ARM9E和ARM10中的改进。它改变EmbeddedICE在触发中断后时入调试模式状态而停止内核运行的弊端,进入一段非常小的中断监控程序中,得到所需要的信息后迅速把控制权转让给先前的任务(这是与远程监控器最大的区别)。在监控程序内处理器完全可以再接收外界的中断和其他触事件,而不是停止运行。这种方式综合了JTAG和远程调试的优点,它可以增加以下两个好处:
・在不禁止中断的前提下调试前景任务(即中断时正在运行的任务);
・不用停止处理器的运行就可以读写和修改存储器(对于机电设备非常重要)。
更为强大的是ARM的实时跟踪解决方案,它由三部分组成:
・嵌入跟踪微核;
・跟踪分析仪;
・跟踪调试软件。
通过这三种工具可实现完全的实时跟踪。跟踪微核存在于芯片,它可以不停止CPU的运行而实时监视芯片总线的信息,并把设定触发范围内的所有信息在CPU运行的同时通过压缩的方式送到外部的跟踪分析仪器里。分析跟踪仪器从芯片外部通过跟踪口(另外一个不同于JTAG的接口)收取信息。因为是压缩的数据,所以分析仪不需要采用与跟踪微核实时跟踪相同的速度。这大大降低了分析的成本,并增加了存储的容量。而PC端的跟踪软件则来自分析仪的数据重新组织起来,从而重现处理器的历史状态和数据、程序流程。同时还可以把执行代码与源代码链接起来,使调试者快速理解跟踪数据。ARM的这种方式通过芯片内部的实时跟踪硬件加上低成本的分析仪器,解决了传统在线仿真器(ICE)和逻辑分析仪的诸多弊端。其示意如图4。
3Nexus标准
自从JTAGIEEE1149.1标准出来后,越来越多的高端嵌入芯片生产商开始采用这个标准。但是1149.1标准只能提供一种静态的调试方法,如处理器的启动和停止、软件断点、单步执行、修改寄存器,而不能提供处理器实时运行时的信息。于是各个厂家在自己的芯片上,把原有的JTAG的基本功能进行了加强和扩展,如前面提到的E-TRACE、背景调试模式BDM(BackgroundDebuggingMode)和片上仿真OnCE(On-ChipEmulation)等,在处理器不停止运行的前提下,进行实时的调试。
由于这些增强的JTAG版本之间各有差异,而且即使同一厂家的不同产品之间也在存着不同。所以一些芯片厂商和调试工具开发公司于1998年成立了Nexus5001论坛,以期提出一个在JTAG之上的嵌入式处理器调度的统一标准。
Nexus将调试开发分成四级,从第一级开始,每级的复杂度都在增加,并且上级功能覆盖下一级。第一级使用JTAG的简单静态调试;第二级支持编程跟踪和实时多任务的跟踪,并欢用户用I/O引脚作为多路复用辅助调试口;第三级包括处理器运行时的数据写入跟踪和存储器的读写跟踪;第四级增加了存储替换并触发复杂的硬件断点。从第二级开始,Nexus规定了可变的辅助口。辅助口使用3~16个数据引脚,用来帮助其他仿真器和分析仪之类的辅助调试工具。其示意如图5。
通过Nexus标准可以解以下问题:
・调试内部总线没有引出的处理器,如含有片内内存器的芯片;
・传统在线仿真器无法实现的高速调试;
・深度流水线和有片上Cache的芯片,能够探测具体哪条指令被取和最终执行;
・可以稳定地进行多内核处理器的调试。
4调试技术的展望
通过上面的分析可以看出,目前的调试技术可以在频率100MHz、内部总线外部不可见、需要进行实时跟踪的情况下分发挥优势,弥补传统的远程调试器和在线仿真器的不足,并且成本非常低廉。
嵌入式远程调试原理研究与实现 篇3
在嵌入式软件开发环境中, 核心开发工具是编译器和调试器[1]。由于嵌入式系统资源 (如CPU速度和内存大小等) 有限, 嵌入式软件调试主要采用远程调试, 如硬件片上调试和软件代理调试两类, 其特点是调试器和被调程序运行在不同的系统中。片上调试实时性强, 但处理器必须支持硬件调试模块, 且针对不同体系结构的So C (System on Chip) 需配备对应昂贵的仿真器[2]。软件代理调试通常需要在目标系统中驻留代理软件, 宿主机调试器与目标机代理软件通信, 调试代理实现对被调程序的控制[3]。该调试方式具有开发成本低、通用性强和可移植性高等优点。
本文首先阐述了嵌入式软件代理调试的基本原理, 提供了代理调试的基本模型, 分析了处理器、嵌入式操作系统、交叉调试器等软硬件模块在嵌入式代理软件调试中的作用和他们之间交互。在此基础上, 结合新型的嵌入式实时操作系统a Coral的基本内核机制, 设计和实现了一款支持GDB的远程调试系统, 并对其中关键调试模块的实现进行了详细讲解, 最后对系统进行了功能验证。
1 嵌入式远程代理调试基本原理
1.1 嵌入式软件远程代理调试模型
嵌入式远程代理调试系统分为宿主机和目标机两个计算机系统[4], 如图1所示。宿主机中有交叉编译器、调试器和被调程序;目标机中有调试代理和被调程序。
交叉编译器 (如arm-elf-gcc) 编译被调程序时, 会从源文件中收集大量的信息[5] (如变量名、变量类型和函数参数等) , 并按照特定的格式写入到可执行文件中。这些信息统称调试符号, 它是将汇编代码和对应的源代码联系起来的桥梁。
宿主机调试器 (如GDB) 负责接收调试人员的调试命令, 结合被调程序可执行文件的调试符号, 将其封装成协议数据包并发送给远端代理[6]。当接收到远端调试代理返回的数据包后, 根据协议规则解析出程序当前状态, 将其提供给调试人员。
调试代理利用目标机操作系统提供的服务建立与被调程序的绑定关系, 接收远程调试器的命令, 控制访问被调程序, 并向调试器返回被调程序的当前状态、被调程序的内存和寄存器信息等信息。
1.2 目标机处理器提供的调试支持
嵌入式软件调试的基本方法有断点、单步执行和栈回溯, 其初衷就是跟踪和记录CPU执行软件的过程, 把动态的瞬间凝固下来供检查和分析[7]。处理器异常机制是代理调试的基础, 每当CPU执行完一条指令后, 会检查是否有异常发生:若没有, 继续下一条指令;否则, CPU硬件将完成权限检查、模式切换、堆栈切换和特殊寄存器保存的工作, 最后跳转到异常处理程序。与调试相关的异常条件有:
(1) 软件断点指令
主流指令集体系结构都包含软件断点指令, 如ARM下的SWI (Soft Ware Interrupt) 指令, 当CPU执行到断点指令时, 便产生一个断点异常。以Linux为例, 异常处理程序便向当前进程发送一个SIGTRAP信号, 内核处理该信号时暂停当前进程并唤醒调试器进程。
(2) 调试寄存器
又叫硬件断点, 是处理器内部保留的专门用于调试的寄存器, 如在ARM So C中Embeded ICE逻辑中的的观察点和调试控制寄存器[8]等。当CPU访存时, 如果访存地址与调试寄存器值进行匹配, CPU便产生一个调试异常。
1.3 目标机操作系统提供的调试支持
调试代理很大程度上依赖目标机的嵌入式操作系统完成调试功能。可将目标机操作系统当成服务提供者, 提供控制、访问、暂停和恢复被调任务的服务, 统称目标机调试子系统。
1) 异常处理程序
异常处理程序是目标机调试子系统的基础, 它将处理器断点事件传递给被调程序的管理者 (调试代理) , 它完成软件调试的两个重要功能:
(1) 保存当前状态
首先必须保存所有通用寄存器, 以记录被调程序暂停时所处的硬件上下文。在调试过程中, 宿主机调试器根据上下文中各个寄存器的值逆向分析出源程序所处的状态。
(2) 触发控制权转换
程序遇到断点后必须暂停, 并通知调试代理处理, 即由调试代理获得对被调程序的控制权。该过程必须由异常处理程序触发 (如在Linux系统中的信号机制) 或者直接完成。
2) 建立绑定关系
在嵌入式软件调试中, 调试代理与被调任务必须建立绑定关系[9]。绑定就是在内核数据结构中建立调试代理与被调任务间的“父子”关系, 其中调试代理为被调任务的“父亲”或接管者。建立绑定关系后, 当程序遇到断点或其他异常事件时, 内核便能准确地找到事件的接管者。绑定即可在被调程序创建时建立, 也可在程序运行期间建立。如在Linux中, 可用ptrace_traceme和ptrace_attach完成绑定, 最终都落实到操作两个程序的TCB (Task Control Block) 的链表关系。
3) 进程控制访问
嵌入式软件调试中, 调试代理需要能够控制被调程序的执行和访问被调程序的地址空间。这些功能是由操作系统内核通过某种接口 (如系统调用) 提供的。如在Linux中的ptrace系统调用, 它能够根据用户态请求的类型来访问被调进程的代码段、数据段、用户态和内核态堆栈等信息, 实现打印变量的值、插入断点和修改变量值等功能。
2 a Coral内核对远程调试的支持
a Coral是多线程嵌入式实时操作系统, 本文将基于a Coral的mini2440 So C (CPU为ARM920T) 版本内核而实现远程调试系统。本节将简要介绍a Coral内核对实现调试代理的支持。
2.1 a Coral线程的基本结构
在a Coral中线程表现为“执行代码+执行环境”, “执行环境”就是线程当前堆栈和寄存器[10]。a Coral提供了比较完善的线程管理模块。
1) 任务控制块TCB
线程TCB由结构体acoral_thread_t实现, 记录了线程堆栈位置、运行状态和调度策略等信息。在调试过程中会触发任务切换, 调度器通过操作TCB等结构完成任务切换。
2) 任务堆栈
每个线程都有一个私有栈, 用于存储函数调用过程中的参数、局部变量值等。在调试实现中将使用该堆栈存储调试栈帧信息。
3) 线程地址空间访问
在a Coral中, 线程之间是共享地址的, 即所有线程都能够直接访问整个地址空间。例如, 对于设置软件断点操作, 首先从对应地址取出原指令并保存, 然后写入断点指令;在删除断点时, 用保存的值重写对应地址。
4) 线程控制
在线程控制方面, a Coral内核提供了完善的接口 (acoral thread类函数) , 包括杀死线程、暂停线程和恢复线程执行等。
2.2 SWI异常处理过程及其不足
a Coral正常运行时, CPU处于系统模式, 当被调线程执行到SWI断点指令后, CPU随即切换到管理模式[10]。a Coral对于SWI异常的处理是系统报错, 并出现系统假死现象。而且, 在管理模式下, a Coral整个系统使用一个栈, 即没有为每个线程创建一个管理模式栈, 因此在该模式下不能进行线程切换。实现调试系统时, 将基于该基本处理过程进行改进。
2.3 应用程序编程接口
a Coral内核提供了完整的嵌入式应用程序编程接口, 调试代理将基于这些编程接口而实现。在网络编程方面, a Coral实现了轻型TCP/IP协议栈LWIP (Light Weight TCP/IP) , 包含了基本的套接字接口和IO多路复用等网络编程函数。此外, a Coral系统提供了字符串操作函数、内存管理函数和输入输出函数等。在线程交互方面, a Coral实现了互斥量、信号量、邮箱和消息等机制及其编程接口。
3 a Coral远程调试系统实现
3.1 基于a Coral的远程调试结构
基于a Coral基本内核机制和对嵌入式远程调试基本原理的研究, 本文设计了a Coral远程调试系统, 如图2所示:宿主机端GDB关联带调试符号的a Coral可执行文件, 通过RSP协议与目标机代理通信[11]。a Coral内核向调代理提供异常、线程绑定和控制访问等服务。
3.2 调试代理的实现
调试代理的实现是对gdbserver (linux下的调试代理) 的裁剪和移植[12], 实现对被调线程的管理和控制, 完成接受宿主机的调试命令、解析命令、调用系统函数执行命令、返回执行结果和管理被调线程等功能。
(1) 通信模块
该模块负责与GDB通信, 包括建立和终止调试连接, 接收调试命令和返回调试结果等。在调试代理开始运行后, 将绑定到一个被调线程, 然后开启调试端口, 监听远程连接。当GDB发起连接时, 通信模块将通知事件监听模块, 进而建立起调试连接。在调试期间, 通信模块获取RSP调试数据包, 通知事件监听模块处理该调试命令。在处理完成后, 接收命令执行模块的执行结果, 封装结果为RSP数据包, 发送给宿主机调试器。
(2) 事件监听模块
该模块循环监听调试代理关注的事件。其主要的事件有远程调试器事件和本地内核事件。前者通知调试代理需要建立调试连接或执行某个调试命令, 例如向被调线程插入断点等;后者来自a Coral内核的SWI异常处理机制, 用于通知调试代理其某个被调线程已经暂停, 进而可以对其进行操作。对于每个事件, 该模块将调用命名解析和执行模块。
(3) 被调线程管理模块
该模块是一个抽象的线程管理模块, 与内核中的线程管理不同, 前者用于调试代理内部记录多个被调线程, 以及管理被调线程的断点等。断点管理通过断点链表方式, 记录线程的所有断点, 其中链表节点包括断点地址, 原始值等信息。被调线程的内部表示, 记录当前被调线程的id号等。
(4) 命令解析和执行模块
命令解析模块根据RSP数据包的格式, 解析通信模块获取到的数据包, 提取出调试命令, 然后调用执行模块。执行模块执行具体的调试命令, 期间它会调用其他模块。例如:调用线程管理模块, 以访问被调线程的断点链表;调用控制访问线程的内核机制, 以实际完成写入断点指令的操作;调用调用通信模块, 以返回当前操作的结果或被调线程的当前状态等。
3.3 a Coral线程绑定的实现
为实现a Coral线程调试, 首先必须在线程TCB中增加一些字段 (如表1所示) , 记录调试代理和被调者的关系等信息。
基于上述数据结构, 线程绑定 (由acoral_create_thread函数) 完成:设置跟踪标志、记录调试器指针、记录异常处理返回地址、设置调试栈帧和初始化父子TCB的链接关系等。相反, 在子线程退出时, 由线程退出函数acoral_thread_exit完成绑定关系的解除。
3.4 SWI异常处理机制的改进
a Coral在管理模式下不能进行线程切换。然而, 在调试中为了暂停当前线程并唤醒调试代理, 在SWI异常处理过程中必须实现线程切换。改进思路:如图3所示, 在SWI异常处理结束, 即退出管理模式并恢复系统模式后, 执行一段回调函数, 该函数完成线程切换、执行环境的保存和恢复, 其关键步骤有:
1) 在硬件异常处理过程中, 硬件保存CPSR到SPSR, 将执行模式从系统模式切换到管理模式, 保存返回地址到LR, 跳转到软件异常处理。
2) 在软件异常处理过程中, 首先检查线程是否被跟踪:若是, 则将上一步LR中的返回地址保存到TCB中, 并把LR设置为回调处理的地址;否则, 进行出错处理, 该过程调试模块并不关心。
3) 软件异常处理完成后, 返回到硬件处理。硬件恢复CPSR模式, 将LR (已经是回调处理的地址) 写入PC。接下来将执行回调处理过程。
3.5 回调过程和调试栈帧机制
由于在异常处理必须保存上下文, 但a Coral没有为调试提供特殊的空间来保存被调线程的上下文。改进方案是在回调过程中建立调试栈帧:在被调线程系统模式下私有栈的栈顶后面存储上下文, 该地址范围称为调试栈帧。调试栈帧的存储结构和回调过程的流程如图3所示, 以下是回调过程步骤说明:
1) 建立调试栈帧, 并保存线程当前上下文;记录栈顶地址到TCB->pt_reg_p中;
2) 用TCB->lr_excp保存的返回地址修改调试栈帧中的pc位置的值;
3) 挂起当前线程;唤醒调试代理并重调度;
4) 当线程被调试代理唤醒后, 用调试栈帧数据恢复执行环境, 便继续正常执行被调线程。
4 调试系统功能验证
本节提供了对调试模型实现的功能测试。其中目标机环境包括mini2440硬件开发板 (cpu是ARM920T) 、a Coral嵌入式操作系统mini2440版本。宿主机环境采用VMware虚拟机、Ubuntu11.10和GDB 7.2。被调线程运行一个排序程序, 包含debugee、quicksort、partition和exchange四个函数, 其中debugee是线程入口函数。根据GDB正常建立调试会话后, 便可执行GDB命令, 如图4所示。
经测试, 本代理能够实现任务级调试, 支持常用的GDB调试命令, 如表2所示。内核提供的调试支持。在此基础上, 结合a Coral的基本内核功能, 设计了远程调试结构, 提出了对a Coral的SWI异常处理过程的改进方法, 实现了线程绑定模块和调试代理。该系统给开发人员调试a Coral应用提供了帮助, 提高了开发效率, 具有无需硬件连接器、开发成本低、可实现任务级调试等优点。文中对于软件调试的软硬件结构的综合分析和总结, 对于理解软件调试具有较好的理论价值;同时, 本文对整个调试系统的实现有较强的实用价值, 为将来在其他新型嵌入式操作系统中实现调试子系统提供了有效参考。
摘要:嵌入式软件调试是多个软硬件模块交互的复杂过程。研究嵌入式远程调试的原理, 包括底层硬件机制、操作系统内核和编译器等模块对目标机调试代理的支持;基于新型嵌入式操作系统aCoral的基本内核功能, 设计aCoral远程调试结构, 提出了SWI异常处理机制的改进方法, 实现了线程绑定机制和远程调试代理。采用GDB (GNU DeBugger) 为宿主机调试器对系统进行功能验证, 结果表明该系统具有可实现任务级调试和稳定性强等优点。
关键词:嵌入式软件,远程调试,aCoral,调试代理,GDB
参考文献
[1]扈啸.嵌入式多核处理器在线追踪调试与错误检测关键技术研究[D].长沙:国防科学技术大学, 2007.
[2]姚放吾, 丁皞.嵌入式远程调试器保护模式下调试功能的实现[J].计算机技术与发展, 2011 (4) :242-245.
[3]Wenyu Chen, Dongpu Han, Dongcheng Tang, et al.A model of remote debugger supporting multiple types of connection[C]//2011 International Conference on Electronics, Communications and Control, 9-11 Sept 2011.Piscataway, NJ, USA:IEEE, 2011:642-645.
[4]王兴杰, 李允, 江浩, 等.基于Linux的嵌入式交叉开发技术[J].计算机应用研究, 2008 (1) :206-208, 214.
[5]张和君, 张跃.基于DWARF的Bootloader远程交叉调试模型[J].计算机工程, 2006, 32 (24) :60-62.
[6]Hongwei Li, Fangsheng Wu, Yaping Xu, 等.Research of"Stub"Remote Debugging Technique[C]//Iccsse 2009:Proceedings of 2009 4th International Conference on Computer Science&Education, 2009:990-994.
[7]张银奎.软件调试[M].北京:电子工业出版社, 2008.
[8]刘鹏, 于立新, 覃辉, 等.常见嵌入式微处理器调试技术综述[J].微处理机, 2011, 32 (4) :16-20.
[9]龚兰兰, 刘晓升, 朱巧明.远程调试系统的关键技术分析[J].计算机应用与软件, 2010, 27 (10) :258-261.
[10]多核嵌入式实时操作系统项目组.aCoral技术文档V1.0[EB/OL]. (2010-09-03) [2012-12-10].http://www.acoral.org/admin/upload/111.rar.
[11]Yang W Y, LEE J Y.PLC Remote Debugger Development Using GDB[C]//2009 International Soc Design Conference.New York:Ieee, 2009:540-543.