引言传统上,调试嵌入式Linux产品需要将硬件和软件工具结合起来,如用JTAG工具进行硬件bring-up,用基于代理(agent-based)的解决方案进行软件开发。这些JTAG和基于代理的工具相结合的方法通常可以解决单点问题,但它们最初并不是专门针对集成化的Linux开发而设计的。因而,在当今集成化的产品开发中,这些传统方法常常是不可行的。但是,我们可以在Linux内核的配置、补丁管理以及在基于Eclipse的IDE环境中的用户空间应用开发、调试
引言
传统上,调试嵌入式Linux产品需要将硬件和软件工具结合起来,如用JTAG工具进行硬件bring-up,用基于代理(agent-based)的解决方案进行软件开发。这些JTAG和基于代理的工具相结合的方法通常可以解决单点问题,但它们最初并不是专门针对集成化的Linux开发而设计的。因而,在当今集成化的产品开发中,这些传统方法常常是不可行的。
但是,我们可以在Linux内核的配置、补丁管理以及在基于Eclipse的IDE环境中的用户空间应用开发、调试和分析之中,将传统JTAG硬件调试融入其中得到一种全新的方法,从而完全改变开发人员使用JTAG连接进行Linux设备软件调试的方法,这就是Wind RiverWorkbench。
Linux设备调试的复杂性
在嵌入式设备领域,Linux的应用正在迅速增加。根据技术市场研究机构VDC的报告,在新的设备研发项目中,有23%会采用Linux。由于开发工作跨越Boot Loader、Linux内核、内核模块和应用,调试工作很可能极为复杂。Linux开发人员必须面对的问题包括为Boot Loader建立目标配置文件,在用户模式和内核模式之间双向对硬Linux虚拟地址、映射内核符号信息以及排除遍布于用户和内核空间之中的差错。包括内核GNU调试器和GNU调试器在内,在基于代理的调试方案中,要想解决上述任何问题都会遇到极大困难。
Boot Loader调试
如果浪费太多的时间在BootLoader的开发与调试上,将会严重影响开发人员对于系统稳定性、设备软件与应用开发的精力投入。因此,开发人员应当借助于先进的工具,尽快逾越这个阶段。
Linux需要依靠BootLoader来启动操作系统。这段代码存放在Flash或者其他非易失性存储器之中,在系统开机或者复位之后立即运行。Boot Loader的调试可能会非常复杂。这段代码与硬件密切相关,在系统启动之后开发人员必须把它从Flash存储重新定位到RAM之中。在今天的SoC处理器中可能包括了数百个配置寄存器,都需要在此时进行初始化,这项工作需要熟悉数千页的特殊设定文档。如果设定寄存器错误,可能导致随后Linux内核或者应用调试的异常。并且手工编辑寄存器设定是一项极为繁琐易错的工作。
Boot Loader开发的另一项常见挑战出现在Boot Loader把Linux装入RAM并启动操作系统的时候。基于代理的调试解决方案不支持BootLoader调试,因为在此过程中还没有开始发挥作用。因此,开发人员只能寄希望于JTAG工具。
JTAG调试解决方案提供了很强的能力来帮助开发人员快速有效地完成Boot Loader的测试与故障排除工作。它使寄存器设置工作大大简化,通过设置硬件断点以及单步执行Flash中的代码,可以快速发现原代码中的错误。IDE可以支持反汇编,还可以让你混合查阅源代码和汇编代码,符号管理功能比较便于代码从Flash向RAM的重新定位,使整个调试工作得到很大帮助。
JTAG调试解决方案不需要通过Boot Loader即可装载Linux内核。对于那些在Boot Loader尚未完成之前就希望开始系统开发的项目管理人员来说,这项功能具有特殊的重要意义。提供了引导行能力的JTAG调试解决方案可以支持Boot Loader和操作系统稳定化的并行开发,从而加速软件开发项目的整体进程。
Linux内核及内核模块调试
Linux内核及内核模块是Linux操作系统的核心构建。在系统被Boot Loader初始化之后,首先装载的就是Linux内核。Linux模块则根据需要进行装载。在进行操作系统bring-up时,开发人员必须专注于Linux操作系统的优化或剪裁以及内核模块的开发,需要必须密切监控硬件与软件之间的互动。Linux内核调试要求具备观察寄存器、数据缓存器及其它底层数据。LinuxKGDB要求具备稳定的Linux内核,并且确保诸如设备驱动之类的客户硬件接口处于就绪状态,其中的代理才能工作。基于代理的调试不具备底层硬件的可视化能力,也不能提供完全的诊断功能,因而无法让开发者了解硬件与Linux内核之间的互动。
如果采用代理来调试Linux内核和内核模块,在进入调试断点时可能会涉及系统暂停或者冻结方面的问题。例如,KGDB无法暂停CPU(特别是在多核或者多处理器环境中)来让开发人员检查CPU的现行状态,它也不能帮助开发人员对崩溃的系统进行调试,因为崩溃的操作系统显然已经不能再运行代理。而且,KGDB还需要以太网等通信接口实现主机系统与目标之间的沟通。总之,采用代理来实现Linux内核模式调试,需要具备由IP栈、稳定的Linux内核和处于运行状态的设备驱动。在上述条件尚未具备,或者上述软件本身还需要调试的时候,基于代理的调试显然就无能为力。
为了实现并验证一个目标系统中的Linux内核,必须拥有可以监控和管理Linux内核和内核模块的全面调试解决方案。基于JTAG的调试解决方案功能特性包括查看局部/全局符号和寄存器以及指令和数据缓存器。已经有商业化的JTAG调试解决方案可以把物理内存和虚拟内存顺畅地映射过来,从而帮助开发人员正确地观察内存地址和内容,也具有对Linux内核模块进行调试的能力,以及在不必反复连接和切断目标系统的前提下多次装载和卸载。
JTAG调试解决方案的另一个重要能力是把系统完全置于暂停状态并且全面观察操作系统和应用的状态。这种能力又被称为“系统模式调试(system mode debug)”,对于Linux内核和Linux内核模块的调试是极为有用的。有了系统模式调试能力,开发人员就可以把整个系统完全暂停下来,包括处理器、操作系统和所有的线程以及中断处理程序。以这种方式暂停系统,就有可能获得系统硬件和软件的完整细节视图,当然也可以让系统继续执行或者分步骤执行某些代码。
因此,在一些KGDB无法使用的情况下,JTAG解决方案就可大派用场,特别是在Linux内核出错或者目标崩溃的情况下更是如此。因此JTAG解决方案在提升操作系统和设备驱动稳定性方面特别有用。