我正在编写在ARM Cortex M3上运行的代码。我使用的是一个与TRACE32软件包一起工作的Lauterbach调试器。
我按照ARM的建议插入了一个软件断点(https://www.keil.com/support/man/docs/armcc/armcc_chr1359124993371.htm),如下所示:
volatile uint16_t haris_4=0;
void function(void)
{
haris_4 = 1;
__breakpoint(0);
haris_4 = 2;
...然后转到TRACE32调试器,观察haris_4变量的值。它的值是1,这意味着断点实际命中了。
我试图跨过断点,继续执行程序,但我做不到。trace32单步、跳过Call和Go的按钮不起作用。
你有什么想法吗?我如何跨越软件断点并继续执行?
发布于 2021-01-23 04:03:11
虽然这个问题听起来很简单,但实际上有几个方面需要考虑:
注意:当你用C/C++编写__breakpoint(0)时,编译器实际上会为它创建汇编指令BKPT 0。(您可以通过单击TRACE32中列表窗口的“模式”按钮来检查汇编程序代码。)
所以首先:在源代码中使用__breakpoint(0) 有什么好的理由吗?我倾向于说:不,在正常情况下,静态断点指令在应用程序代码中是没有意义的。如果您想在某些指令处停止以观察变量,请使用命令Break.Set在TRACE32中设置断点,或转到菜单→Break→Set...
如果您需要在闪存中设置断点,调试器将自动设置片上断点。(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指令是故意添加到源代码中的,则可能会非常恼人,因为您不能跳过它。
因此,当执行一条TRACE32指令时,BKPT做了一个小把戏,并将程序计数器设置为BKPT指令下的指令。因此,BKPT指令在单步执行时的行为类似于NOP。
但是,您必须使用TRACE32版本R.2014.09或更高版本。
如果你的TRACE32版本比较旧(所以你已经6年没有更新过了),那么你仍然可以让它与实践脚本一起工作:
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命令行中的以下命令的下一个instruction).
GLOBALON PBREAK DO myfix.cmm
该命令将在程序执行停止时运行脚本myfix.cmm,例如,由于BKPT instruction.You可能想要将该GLOBALON命令添加到您执行的实践脚本中以启动调试会话。
但是,如果您已经从2015年或更新版本开始使用TRACE32,请同时检查TRACE32中的窗口PMACRO,以确保没有人或您的同事用另一种GLOBALON PBREAK处理程序恶作剧过您。
https://stackoverflow.com/questions/65823103
复制相似问题