虽然这个问题听起来很简单,但实际上有几个方面需要考虑:
- 为什么有人要在他/她的里面有断点指令
代码?
- 执行断点时处理器是否处于调试模式
指导?
- 是否使用了相当旧的 TRACE32 版本?
注意:当您在 C/C++ 中编写 __breakpoint(0) 时,编译器实际上会为其创建汇编指令 BKPT 0。 (您可以通过点击TRACE32中List窗口的“Mode”按钮查看汇编代码。)
首先:你的源代码中有__breakpoint(0)的充分理由吗?我倾向于说:不,在正常情况下,静态断点指令在应用程序中没有任何意义代码。
如果您想在某些指令处停下来观察您的变量,请使用命令Break.Set 在 TRACE32 中设置断点或转到菜单 → 中断 → 设置...
如果需要在 Flash 中设置断点,调试器会自动设置片上断点。 (TRACE32 还允许您在闪存中设置软件断点,如果您真的想要这样做(但这有点棘手)。)
但是,如果您真的想在源代码中包含 __breakpoint(0),让我们看看为什么这可能无法如您所愿...
我们来看第二点:处理器在执行断点指令时是否处于调试模式?
如果您在连接调试器之前执行代码,则执行 BKPT 指令时您的 CPU 可能未处于调试模式。在这种情况下,CPU 将跳转到异常向量。根据您对调试停止控制和状态寄存器 (DHCSR) 的配置,这将是一个 DebugMonitor 或 HardFault 异常。在这两种情况下,您的程序计数器可能不再在您的函数中,并且当您按下 TRACE32 中的步进按钮时,会执行一些完全不同的代码。 (在“ARMv7-M Architecture Reference Manual”的“调试事件行为”一章中了解更多信息)
当您点击 TRACE32 中的步进按钮时,请检查您的程序计数器 (PC) 是否实际上仍指向 BKPT 指令。 (例如,在菜单 → 查看 → 注册中检查 PC 的值。)如果 PC 值正常,这可能是另一个问题...
最后:你的 TRACE32 版本比较旧吗?在这种情况下我们可以做些什么......
当 Cortex-M CPU 在调试模式下执行 BKPT 指令时,CPU 将在该 BKPT 指令处停止,并且程序计数器 (PC) 将指向该 BKPT 指令。此外,单步执行 BKPT 指令将使 PC 停留在 BKPT 指令上。虽然如果 BKPT 指令是由调试器动态插入的,CPU 的这种行为很好,但如果 BKPT 指令是故意添加到源代码中的,则可能会很烦人,因为您无法跳过它。
因此,当执行 BKPT 指令时,TRACE32 做了一个小技巧并将程序计数器设置为 BKPT 指令下方的指令。因此,BKPT 指令在单步执行时的行为类似于 NOP。
但是您必须使用 TRACE32 版本 R.2014.09 或更新版本。
如果您的 TRACE32 版本较旧(因此您已经 6 年没有更新),那么您仍然可以使用 PRACTICE 脚本使其工作:
- 创建一个文本文件并命名它,例如myfix.cmm
- 在该文本文件中输入以下两行代码:
IF (ADDRESS.INSTR.LEN(P:R(PP))==2)&&((DATA.WORD(P:R(PP))&0xff00)==0xbe00)
Register.Set PP R(PP)+2
此脚本检查当前程序指针 (PP) 处的指令是否具有两个字节的大小,以及它是否具有 BKPT 指令的 Thumb 机器代码。如果是,脚本会将程序指针增加 2(“跳转”到下一条指令)。
- 在TRACE32命令行中执行以下命令:
GLOBALON PBREAK DO myfix.cmm
该命令将在程序执行停止时运行您的脚本 myfix.cmm,例如由于 BKPT 指令。您可能希望将该 GLOBALON 命令添加到您执行的 PRACTICE 脚本中以启动调试会话。
- 就是这样:下次 CPU 因 BKPT 指令而停止时,它会感觉它在 BKPT 指令之后停止,并且在单步执行时表现得像 NOP。
但是,如果您已经拥有 2015 年或更新版本的 TRACE32,还请检查 TRACE32 中的窗口PMACRO,以确保没有人或您的同事使用其他类型的 GLOBALON PBREAK 处理程序来恶作剧....