调试嵌入式应用程序 Debugging

文摘   2024-11-19 07:03   上海  
软件和硬件的相互依赖性使嵌入式设计中的调试变得复杂。新方法正在逐渐成熟,以帮助减少调试时间。
随着硬件和软件之间观察到的和可能的交互数量不断增加,以及越来越多的功能被塞入芯片、封装和系统中,调试嵌入式设计变得越来越困难。但在这方面似乎也有一些进步,涉及多种技术,包括硬件跟踪、基于扫描链的调试以及更好的模拟模型。
其中一些是由于新工具,一些是现有工具的组合,还有一些涉及方法的变化,即在设计到制造流程的不同时间以不同的组合使用工具。
“根据触发事件跟踪和捕获内部信号,并将它们存储在跟踪缓冲区中,然后可以从调试端口读取,这样就可以无缝收集数据而不会中断系统的正常执行,”Valtrix Systems 首席执行官 Shubhodeep Roy Choudhury 说。 “可能需要很多硬件仪器,但将触发事件置于故障点附近可以对问题产生很大的可见性。”
最大的挑战之一围绕着在嵌入式上运行的软件。“测试该软件非常困难,”MachineWare CTO Jan 说道。“我记得作为一名工程师,我试图获得原型。你必须分时使用它们,因为你永远没有足够的原型。使用模拟改变了为嵌入式世界开发软件的能力,因为如果你能为你的平台建立一个好的模拟模型,这意味着你可以测试和运行它,并将其放入回归农场,实现持续集成等。你可以获得更高质量的软件,因为你有更多的机会来验证它。但说到调试,就目前模拟的情况而言,它比在原型或硬件上调试要高效得多,而且你可以获得一些巨大的好处——版本控制、可控性、可观察性,以及抽象和停止在你想要的地方的能力——然后看到一切。使用模拟器,您可以获得其他方式无法获得的可观察性。”
随着不同类型的芯片和内存被添加到设计中以提高性能和降低功耗,情况变得更加复杂。
“在异构系统中,典型的系统将具有来自多个不同供应商的 IP 块,以及在某些情况下由 SoC 开发人员内部团队提供的 IP 块,以及来自非传统 IP 供应商的 IP 块,”Cadence IP 集团产品营销总监 George Wall 表示。“如果他们从另一家 SoC 公司获得了硬件模块的许可,那么每个公司都有自己的一套标准和自己的实现。所以它是一种非常异构的设备。如何在调试级别集成所有这些?这是一个挑战。我们确实在调试方面支持开放标准,许多其他商业供应商也是如此。但内部 IP 和来自非传统地方的 IP 可能来自不支持这些标准的公司。”
这增加了另一层复杂性,因为工程团队正在处理一些黑匣子。他们不知道里面是什么,也不想对它们进行太多的修改。“他们只是想确保外部可见,这样他们就能看到发生了什么,” Wall 说。“实际上没有行业标准来规定‘好吧,这是合适的可见度’。所以这是一个挑战。”

图 1:Cadence/Green Hills 工具集成用于嵌入式系统设计


提高可见性
但新方法可以创造新的效率,Jan 说。“我们已经看到工程师试图让他们的固件与操作系统一起运行,编写跟踪和抽象事物,以便不仅在变量级别或功能级别进行监控,而且可以探测操作系统并观察操作系统正在做什么。他们可以跟踪这一点。这意味着他们不会得到十亿行指令跟踪,而是会得到几千行函数跟踪或调度程序跟踪,这样他们就可以观察正在发生的事情并在高层次上可视化其中的一些。然后当出现问题时,他们可以深入研究。例如,一个用户实施断言来监控操作系统,如果发生了什么事情,它就会出错。它在跟踪中保留了一个滚动缓冲区,比如说,10,000 条指令和 1,000 个函数构建。当它停止时,他们可以回头看看当时发生了什么。
这可以在硬件中完成,但并不容易。“你必须把一切都内置进去,”他说。“有了模拟器,工程团队可以编写自己的模拟器,扩展它,并构建自己的工具,以获得更好的可视性,他们可以插入断言来更好地监控事物,并指出可能不是致命的但仍会影响性能的错误。这关乎可见性和可观察性。如果你正确使用模拟器,没有什么是黑匣子。”
在通用硬件上运行的调试软件应用程序与嵌入式应用程序之间的巨大区别在于它运行的独特硬件。
“一般来说,这是专门为特定应用构建的东西,而不是遗传计算节点,”Synopsys 研发高级经理 Sam Tennent 说。“关键在于硬件相关软件之间的交互,这是最底层的一层,软件必须知道硬件。在那上面会有从硬件中抽象出来的层。我们看到,与硬件对话的层面以及由此引发的具体问题引起了人们的兴趣,这些问题与高级软件中可能出现的问题不同。
调试工程师需要对硬件有所了解,他说。“他们需要了解设备寄存器、中断等信息——所有这些发生在硬件层面的事情都会影响软件的运行。他们真正需要的不仅仅是了解软件领域发生的事情,还有硬件领域发生的事情。他们需要能够将这些事情关联起来。”
虚拟原型是解决这一问题的一种方式。“虚拟原型使用硬件的抽象模型,这意味着您可以同时了解硬件层发生的事情,以及软件中发生的事情,” Jan 说。“通常您可以将这些事情关联起来。您可以查看软件中的事件,也可以查看软件例程,并准确了解它们如何与硬件交互,例如,如果您知道硬件会引发中断,则可以跟踪该中断,并可以准确了解软件对此的反应。当您在那个级别调试问题时,这非常有用。
纯软件模拟器仍然可用于更高级别的调试,但通常不用于对硬件寄存器等进行建模。“它们有一个高级 API,软件正在使用它,但它们并没有在寄存器级别进行建模,”Tennent 说。“这意味着您在那个级别遇到的任何问题都不会被这些软件模拟器之类的东西发现。”
Jan 指出,当处理器模型封装在 Verilog 中时,工程团队便可以使用 Cadence、西门子 EDA 和 Synopsys 工具进行调试。“他们可以在我们的调试器中调试软件堆栈,并在一次模拟中完成所有调试。由于它们是单步执行的,因此他们可以看到 Cadence 设备中的波形,并且可以在一次模拟中查看硬件和软件。这不是一个调试器,因为从概念上讲,硬件中有信号和线路,但它可以在一次运行中完成并同步,以便工程师可以单击软件中的某个点并查看波形在那个时间点正在做什么。”
Cadence 的 Wall 建议工程团队提前考虑如何确保系统上运行的固件的调试。“考虑固件和 SoC 中的其他设备之间将发生的交互类型,”他说。“考虑如何获得对这些交互的可见性。 CPU 级别的一种常见方法是实现跟踪功能,其中跟踪输出至少可用于告诉您发生某些事情时正在运行的代码。在系统级别还需要做很多事情来确保这些交互的可见性。可以添加特殊的可见性寄存器来定期检查提供系统状态的嵌入式固件。还有其他技术可以在系统中的其他块中实现跟踪检测,这些技术可以由处理器上运行的固件控制或启用。因此,如果它难以与某个特定块交互,它可以打开该块的跟踪,然后从内存位置读取跟踪以了解问题。”

改进低级软件调试
根据应用程序是处于裸机级别还是具有 RTOS,也会有所不同。
“基于这两个分支的应用程序总是使用一些集成开发环境进行调试,这是您调试某些东西时的主要切入点,”Vtool 嵌入式软件负责人 Haris Turkmanovic 说。 “调试过程的复杂程度取决于集成开发环境的复杂程度。如果有一个开发良好的集成嵌入式环境,调试就会容易得多。”
那么调试过程是什么样的呢?“你首先需要知道会发生什么,”Turkmanovic 说。“如果这个期望没有得到满足,你就知道有问题了。这个期望基于各种值,这些值是内存的一部分。当你调试某个东西时,你需要进入内存,查看内存内容以了解它是如何变化的,一步一步地检查你的代码。每个调试过程都包含迭代。你一步一步地检查你的代码,观察内存内容以查看是否有异常行为。然后你就可以发现问题。基本上,你正在观察内存以查看内容是否按预期写入。如果不是,那么你就可以定位问题。如果你有一个大系统,你可以将它分成几个部分,然后分别查看每个部分。如果有某种操作系统,这个过程会更容易,因为运行嵌入式系统的嵌入式平台非常复杂。它们通常有一个内存保护单元,例如,允许你将内存分成多个区域。如果你想从一个区域访问另一个区域的部分代码,MPU 会注意到。当你有操作系统时,第二种方法是使用内置函数,它将监视程序的执行情况。如果你尝试做一些计划外的事情,这个函数将被调用,那里的断点可以捕获错误。

提高调试过程的效率需要系统的方法
Turkmanovic 表示:“这种系统化方法的切入点是了解您的期望和限制。”“如果您没有系统化的调试方法,如果您只是通过猜测进行调试,那么您可能会陷入无限循环,调试将永无止境。如果您没有期望,也没有系统化的方法,那么调试将非常困难。例如,如果您尝试以高于系统速度的速度获取数据,那么您将始终遇到错误,因为您无法完成不可能的事情。”
在使用自动生成的代码和/或自定义配置的情况下,处理器核心验证的自动化尤为重要。形式化验证技术在这里起着关键作用。
“形式化验证比模拟提供更快的运行时间,允许释放模拟许可证以用于其他任务,例如集成测试,”西门子旗下 OneSpin 营销主管 Rob van Blommestein 指出。“设置也更快更容易。RISC-V 创建自定义指令的灵活性为模拟设置了验证障碍。形式化技术可轻松应用于验证自定义扩展和指令。使用形式化技术,无需付出任何努力即可完全覆盖所有极端情况,而无需在测试平台开发过程中付出任何努力。使用形式化技术还可以发现未指定的行为,例如未记录的指令。工程团队将能够在整个验证过程中了解与 ISA 要求相关的覆盖进度。可以实现验证和覆盖的直接可追溯性。”
形式化验证技术中的新技术还有助于验证断言集是否足以覆盖 RISC-V 核心设计,并确保没有未经验证的 RTL 代码。
“设计中的任何额外功能,包括硬件木马,都会被检测并报告为违反 ISA。这包括系统地发现任何隐藏的指令或指令的意外副作用。总体而言,形式化技术能够以更少的努力提供更高质量的结果,”van Blommestein 补充道。
对于嵌入式 Linux 代码,情况变得更加复杂。 “我们拥有多线程、多处理器系统,使用某种可以逐步执行、检查内存或其他操作的调试器进行调试并不容易,”Vtool 嵌入式软件 Linux 负责人 Gradimir Ljubibratic 说道。“在 Linux 世界中,我们主要依靠实时调试块和调试事件。我们可以看到系统正在发生什么、系统如何波动、不同组件如何交互等等。在我们尝试在真实系统上测试所有内容之前,我们使用单元测试来测试系统的不同小组件。我们目前正在实施持续集成测试,以帮助我们在开发早期阶段检测错误。此外,可以使用不同的工具进行内存分析,以检查代码正在发生什么,是否存在某种堆栈溢出或内存违规等。这主要与用户空间开发和应用程序开发有关。”
西门子 EDA EPS IDE 团队的工程经理 Taimoor Mirza 表示同意。 “在现代软件开发中,必须覆盖多个 SoC 上多个内核的多个线程,并且每个组件都需要与系统中的其他组件进行通信,传统的调试技术很快就会达到极限。这些对于跟踪单个线程/内核上的故障非常重要且必要,但为了全面了解调试,需要扩展视图。这就是分析和分析工具发挥作用的地方,它们有助于分析和理解复杂的系统行为并帮助追踪这类问题。用户可以概览整个系统的行为,从而轻松发现出现问题的区域,例如网络问题、操作系统的调度问题、设备驱动程序问题。工具还可以导入外部记录数据并与软件跟踪同步显示。”

图 2:使用复杂测试平台进行调试。

还可以将跟踪点添加到代码中以扩展可用性,而 API 允许创建自定义代理来理解这些跟踪点,以便更好地支持用户提供在何处搜索问题的提示,Mirza 说。“此外,IDE 固件开发人员可以添加仪器并将其用于自己的代理中,以帮助最终用户查找更高级别代码的问题。一旦问题区域被归零,用户现在就可以使用针对特定问题的技术来尝试获取更多详细信息。”
例如,如果用户在 Linux 内核或内核模块中发现问题,则可以使用工具来帮助调试 Linux 内核或内核模块。如果用户遇到 RTOS 问题,则可以使用 RTOS 感知功能来提供有关该问题的其他信息。
一般来说,Mizra 说,在解决任何情况时,都有一些技巧和技术可以提供帮助。例如,通过使用 -O0 -fno-inline 使代码更易于调试,这会禁用优化和内联,这样您就可以逐步执行所有代码,并且自然而然地执行。您还可以使用 -Og 而不是 -O0 来专门优化调试。本质上,这要求优化器协助调试能力,而不是妨碍它或被禁用。
还有多种其他技术可用。此外,调试团队可以使用静态分析工具,例如 Klocwork、valgrind 套件等,这些工具带有学习曲线,有时会给出误报,但它们可以发现您甚至没有寻找的问题,因此最好在开发早期使用它们,然后持续使用。
在模拟器上尽早运行项目可以实现更好的远程和并行开发,以及更好的高级测试自动化。此外,优化编辑-构建-调试周期确实可以在以后获得回报。还可以创建开发脚本、调整 makefile 和调整 IDE 以自动实现最快的构建和加载。这些调整会对调试计划和整体上市时间产生重大影响。

安全问题
安全也正在成为开发人员关注的重点。“安全要求和调试可见性之间存在着天然的矛盾,”Wall 说。“SoC 设计师在 SoC 运行时想要获取的信息也可能存在漏洞,但对黑客来说却很有价值。你不能孤立地考虑这些方面。你必须提前考虑所有这些部分将如何相互作用。它必须提前设计架构。”
Synopsys 软件完整性小组首席安全顾问 Mike Fabian 表示:“我合作过的大多数组织都没有专注于更好的调试实践。弹性、质量和安全都是不同成熟度级别的组织的目标。他们专注于使用最新进展尽早发现错误,以确保常规版本具有弹性并达到可接受的安全级别。需要强制使用经过审查的设计蓝图、明确的 SDK/框架/编码标准、供应链尽职调查、保护客户隐私的主动机制以及自动化治理和技术护栏,以尽早避免可预防的错误。在开发周期的后期调试问题,假设调试意味着‘此代码未按预期工作’,这是这些流程和控制的失败。更快、更早地发现错误更具成本效益。”

结论
最后,由于后期的错误始终会对进度造成风险,因此除了调试技术之外,还应高度重视刺激和测试生成器。 Valtrix 的 Roy Choudhury 表示:“在设计生命周期的早期启用软件驱动的刺激和实际用例会增加遇到复杂错误的机会。”“而且由于应用软件的开发并不以寻找设计错误为目的,而且调试起来通常很复杂,因此使用可以更好地运行系统并利用系统中现有的调试基础设施的刺激生成器始终是一个好主意。”

软硬件协同设计 HW-SW Co-Design
欢迎后台留言,AI 客服全天在线。脱离物理硬件,开发测试和调试软件。基于虚拟原型的软硬件协同设计,提前一年实现产品上市创收,降低一半开发时间。
 最新文章