2026-08-29
Stack Overflow: View Question
Tags: c, visual-studio-code, gdb, embedded, stm32
Score: 1 | Views: 153
The asker is debugging an STM32L475 in STM32CubeIDE for VSC. They've defined a define hook-stop in their .gdbinit that runs on every stop event — typically for auto-refreshing peripheral views, dumping registers, or logging. It fires reliably for manual breakpoints and after ordinary continue/step completions, but is silently skipped when a next or step is aborted mid-flight by a hardcoded __BKPT (ARM software breakpoint instruction) inside a macro like assert().
Why it's interesting: This sits at the seam between GDB's stop-event machinery and the ARM Cortex-M's BKPT exception semantics. Stepping in GDB uses either single-step hardware assist (DWT/FPB or the DHCSR C_STEP bit) or a temporary "step-resume" breakpoint. When the CPU executes a literal BKPT #0 instruction, the debug halt reason reported to GDB is SIGTRAP with a signal subcode, not "step completed." GDB's internal state machine treats this as a distinct stop class — specifically TARGET_WAITKIND_STOPPED with a breakpoint hit that wasn't in GDB's own breakpoint table. In some GDB paths, particularly when a step operation is "interrupted" rather than "completed," the normal normal_stop flow (which fires hook-stop and the Python stop event) is bypassed in favor of a shortcut that just reports the signal.
Approach:
set debug infrun 1 and set debug remote 1. Compare the stop packets for a normal breakpoint vs. the __BKPT-triggered one — you'll likely see T05 hwbreak vs. T05 swbreak, or a plain S05.hook-stop: gdb.events.stop.connect(handler). The Python stop event fires from a slightly different code path and often catches cases hook-stop misses. Inspect the event type — SignalEvent vs. BreakpointEvent vs. StopEvent.catch signal SIGTRAP with commands as a belt-and-suspenders trigger.__BKPT in the assert macro with __asm__("bkpt #0") wrapped so GDB's swbreak handling kicks in cleanly, or install a fault handler that traps in software and calls a normal breakpoint location GDB knows about.Gotchas: STM32CubeIDE ships a modified GDB and may inject its own hook-stop that overrides the user's. The behavior also differs between arm-none-eabi-gdb 12.x and 15.x — the swbreak/hwbreak stop-reply handling was reworked. And on Cortex-M, an unhandled BKPT outside of debug context escalates to HardFault, which is a completely different code path — verify the CPU is actually halting on the BKPT and not fault-vectoring.
hook-stop only wires into some of them — hardcoded BKPT instructions during an active step operation land in a path that skips it entirely.