问题描述
我使用的是 STM32 Cube IDE,我经常收到一个错误对话框,内容为:
Failed to insert all hardware breakpoints;
you may have requested too many hardware breakpoints/watchpoints
我知道我使用的 ARM Cortex M0+ 仅支持 4 个硬件断点,因此会出现错误,但这通常还不够。我该如何解决这个问题,并设置 4 个以上的断点?
请注意,我之前曾使用过 STM8(使用 IAR EWB),这是一个更加有限的 MCU,但我可以根据需要使用任意数量的断点。
解决方法
除了硬件断点,软件断点也可以用来闯入调试器。仅当代码位于 RAM 中时,调试器才支持此功能。这通常根本不实用。
作为一个生活窍门,可以做的是创建包含硬件断点的 breakpoint()
函数。现在无论在何处调用此函数,都会激活断点:
void __attribute__ ((noinline)) breakpoint()
{
__asm("NOP"); // <---- set a hardware breakpoint here!
// hello,please Step Out to go to caller location (ex: press Shift-F11)
}
void main()
{
int x = 1;
breakpoint(); // break into the debugger
printf("%d\n",x);
x += 2;
breakpoint(); // break into the debugger,again
printf("%d\n",x);
}
调试器现在将在 breakpoint()
内停止。要查看断点的实际位置,必须退出。
此技术为单步等交互释放了硬件断点,而 4 个可用断点通常就足够了。
注意事项:
-
breakpoint()
函数的替代方法是使用__asm("BKPT #0")
,它进入调试器。不幸的是,没有办法跳过这条指令(在 STM32/GDB 上测试),所以它的作用就像一条 HALT 指令。它可用于在故障条件或未使用的中断中放置断点。 - 当
breakpoint()
被省略时,__asm("NOP");
函数似乎只工作一次 - 就 STM8 而言,它特别有一个支持字节更新的闪存,因此它的工作方式与 RAM 非常相似。调试器可以根据需要使用它来插入软断点。
- 不过,STM8 只有 2 个断点寄存器,它们可能专门用于单步执行。
- 其他更强大的 ARM Cortex MCU 可以有 6 或 8 个硬件断点。
- GDB(和其他调试器)在处理断点方面可能会更聪明一些。例如,当您在一个函数中有多个断点时,通常不可能在遇到某个断点之前 命中它上面的断点。在某些常见的调试场景中,这可能会大有帮助。
ARM 调试外设的硬件断点数量有限。
某些调试探针(例如 SEGGER J-Link)可以通过插入 bkpt 指令来设置“软件”断点并动态重新编程闪存。您可以使用 __BKPT()
内在函数设置自己的软件断点。
#ifdef DEBUG
#define DEBUGBKPT() __BKPT()
#else
#define DEBUGBKPT()
#endif
如果您使用 stlink-V2,您可以将其转换为 Segger,并通过使用以下链接中的软件从无限断点和更快的调试中受益:https://www.segger.com/products/debug-probes/j-link/models/other-j-links/st-link-on-board/