如何解决:插入所有硬件断点失败;您可能请求了太多的硬件断点/观察点

问题描述

我使用的是 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/