debug-trace-patterns
/debug-trace-patterns
Cortex-M debug patterns: CFSR decoding after a HardFault, addr2line from fault PC to source line, GDB commands for live faults, stack canaries, ITM printf, and DWT data watchpoints. Use when chasing a crash, a hang, or memory corruption on target.
- Author
- ormus-solutions ↗
- Repository
- libreembed-claude-code ↗
- Licence
- MIT
- Last repository change
- 09.10.2026
Assessment and security
- Files in this package
- 1
- Scripts
- 0
- HTML comments
- 0
- URLs in SKILL.md
- 0
No signals detected. Repository changed on 09.10.2026, without references to retired models or APIs.
MIT, open: use and modify while retaining author attribution.
What it does and when to use it
Cortex-M debug patterns: CFSR decoding after a HardFault, addr2line from fault PC to source line, GDB commands for live faults, stack canaries, ITM printf, and DWT data watchpoints. Use when chasing a crash, a hang, or memory corruption on target.
Original author description
Cortex-M debug patterns: CFSR decoding after a HardFault, addr2line from fault PC to source line, GDB commands for live faults, stack canaries, ITM printf, and DWT data watchpoints. Use when chasing a crash, a hang, or memory corruption on target.
How it works
- Knowledge Base
- Pattern 1: Decode CFSR After HardFault
- Pattern 2: addr2line — Fault PC to Source Line
- Pattern 3: GDB Commands for Live Fault Debugging
- Pattern 4: Stack Corruption Detection with Canary
- Pattern 5: ITM Trace Printf
- Pattern 6: DWT Data Watchpoint (without debugger)
- Anti-Patterns
- References
SKILL.md preview
---
name: "debug-trace-patterns"
description: "Cortex-M debug patterns: CFSR decoding after a HardFault, addr2line from fault PC to source line, GDB commands for live faults, stack canaries, ITM printf, and DWT data watchpoints. Use when chasing a crash, a hang, or memory corruption on target."
---
# debug-trace-patterns
## Knowledge Base
Practical debug patterns for ARM Cortex-M firmware. Tools: OpenOCD, GDB, J-Link, logic analyzer.
---
## Pattern 1: Decode CFSR After HardFault
Given a CFSR value (e.g., from `monitor mdw 0xE000ED28`), decode:
```
CFSR = 0x00020000 → UFSR.INVSTATE (bit 17)
Cause: Attempted to execute code with Thumb bit cleared in xPSR.
Common cause: function pointer stored with bit 0 cleared (missing |1 for Thumb).
CFSR = 0x00000400 → BFSR.IMPRECISERR (bit 10)
Cause: Imprecise bus error. BFAR is not valid.
Common cause: DMA write to invalid address, async fault from write buffer.
Fix: set SCB->CCR |= SCB_CCR_BFHFNMIGN_Msk temporarily to locate source.
CFSR = 0x00008200 → BFSR.PRECISERR + BFSR.BFARVALID
Cause: Precise data bus error. BFAR = 0xE000ED38 contains fault address.
Common cause: null pointer dereference, access to unmapped memory region.
CFSR = 0x02000000 → UFSR.DIVBYZERO (bit 25)
Cause: Integer divide by zero.
Fix: enable div-by-zero trap: SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk.
```
---
## Pattern 2: addr2line — Fault PC to Source Line
```bash
# Convert stacked PC to source file + line number
arm-none-eabi-addr2line -e firmware.elf -f -i 0x08003A24
# Output:
# sensor_read
# /home/user/project/src/sensor.c:87
# Also inspect LR to find the caller:
arm-none-eabi-addr2line -e firmware.elf -f -i 0x080038F6
```
The `-i` flag follows inline function chains.
---
## Pattern 3: GDB Commands for Live Fault Debugging
```bash
# Full embedded debug session
arm-none-eabi-gdb firmware.elf
(gdb) target remote :3333 # OpenOCD GDB server
(gdb) monitor reset halt
(gdb) load
# After a fault occurs:
(gdb) info registers # All CPU registers
(gdb) p/x *((uint32_t*)0xE000ED28) # CFSR
(gdb) p/x *((uint32_t*)0xE000ED2C) # HFSR
(gdb) p/x *((uint32_t*)0xE000ED34) # MMFAR
(gdb) p/x *((uint32_t*)0xE000ED38) # BFAR
(gdb) x/16xw $sp # Stack dump
(gdb) backtrace # Unwind stack (requires -g and no -O2 optimization)
# Watchpoints: halt when variable changes
(gdb) watch g_critical_var
(gdb) rwatch *(uint32_t*)0x20001000 # Hardware read watchpoint (DWT)
```
---
## Pattern 4: Stack Corruption Detection with Canary
```c
#define STACK_CANARY_VAL 0xDEADBEEFUL
/* Place canary at bottom of task stack (lowest address, first to overflow) */
void stack_canary_init(uint32_t *stack_bottom, uint32_t depth)
{
for (uint32_t i = 0; i < depth; i++) {
stack_bottom[i] = STACK_CANARY_VAL;
}
}
/* Call periodically or from idle task hook */
bool stack_canary_check(const uint32_t *stack_bottom, uint32_t depth)
{
for (uint32_t i = 0; i < depth; i++) {
if (stack_bottom[i] != STACK_CANARY_VAL) {
return false; /* Overflow: canary corrupted */
}
}
return true;
}
```
FreeRTOS alternative: `uxTaskGetStackHighWaterMark(NULL)` returns minimum free stack words ever observed for the current task.
---
## Pattern 5: ITM Trace Printf
```c
/* Retarget printf to ITM port 0 (SWO output) */
int _write(int fd, const char *buf, int len)
{
(void)fd;
for (int i = 0; i < len; i++) {
ITM_SendChar((uint32_t)buf[i]);
}
return len;
}
/* ITM enable in SystemInit or debug init: */
void itm_enable(uint32_t cpu_freq, uint32_t swo_freq)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
/* SWO prescaler: cpu_freq / swo_freq - 1 */
TPI->ACPR = cpu_freq / swo_freq - 1U;
TPI->SPPR = 2U; /* NRZ (UART) encoding */
TPI->FFCR = 0x100U;
ITM->LAR = 0xC5ACCE55UL; /* Unlock ITM */
ITM->TCR = ITM_TCR_ITMENA_Msk | ITM_TCR_SYNCENA_Msk | (1UL << 16);
ITM->TER = 0xFFFFFFFFUL; /* Enable all 32 stimulus ports */
}
```
Host: ST-Link SWV viewer in STM32CubeIDE, or J-Link SWO Viewer, or OpenOCD `tpiu` + PuTTY serial.
---
## Pattern 6: DWT Data Watchpoint (without debugger)
Use DWT comparators to detect writes to a specific address at runtime:
```c
/* Trigger DebugMon exception when address 0x20001234 is written */
void dwt_set_watchpoint(uint32_t addr)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk | CoreDebug_DEMCR_MON_EN_Msk;
DWT->COMP0 = addr;
DWT->MASK0 = 0U; /* Match exact address */
DWT->FUNCTION0 = 0x6U; /* Data write watchpoint → DebugMon */
}
/* DebugMon_Handler fires instead of halting (no debugger attached) */
void DebugMon_Handler(void)
{
DWT->FUNCTION0 = 0U; /* Disable watchpoint */
/* Log PC, LR for analysis */
}
```
---
## Anti-Patterns
- **Using printf for timing analysis**: printf is slow (UART or ITM) and perturbs timing. Use DWT->CYCCNT or toggle a GPIO on oscilloscope.
- **Compiling with -O0 always**: some bugs are optimizer-sensitive. Debug with -Og (debug optimizations) to get accurate backtraces while keeping most debug info.
- **Ignoring IMPRECISERR**: it means the fault address is not directly available. Enable BFHFNMIGN + process in NMI to find the source.
- **Not initializing DWT before using cycle counter**: CoreDebug->DEMCR bit must be set first, or DWT->CYCCNT stays 0.
## References
- ARM CoreSight Architecture Specification: IHI0029
- OpenOCD documentation: openocd.org/doc/html/
- Percepio Tracealyzer: trace tool for FreeRTOS
- "Hard Fault Analysis" by Joseph Yiu (ARM community blog)
Versions
The database has no other skills named debug-trace-patterns.
Database snapshot: 13.11.2026 · package version 61dd66692eb9 (SHA-256 digest of the entire package)
Downloads in the last 30 days: 0 · ranking
Report a problem with this skill: harmful content, incorrect descriptions or an author’s removal request.
Similar skills
- 100gdb
Use when running GDB: breakpoints, watchpoints, segfault or hang debugging, reverse debugging, remote gdbserver, core dumps, pretty-printers, Python scripting, or multi-threaded debugging. - 100cortex-m-patterns
Cortex-M code patterns for SysTick, NVIC priority grouping, FPU enable, MPU regions, AAPCS inline assembly, DWT cycle counting, vector table relocation, and WFI sleep entry. Use when writing core-level Cortex-M code or checking it against a known-good pattern. - 100hardfault-triage
Use when triaging processor exception crashes — HardFault, MemManage, BusFault, UsageFault, data/prefetch abort, illegal instruction, or watchdog timeout. Covers fault-register interpretation, stack-frame extraction, PC-to-source resolution, and root-cause classification. - 81fault-forensics
Analyze embedded panic logs, Cortex-M fault registers, core dumps and addresses against the matching firmware ELF. Use when requests involve HardFault, BusFault, UsageFault, reset crashes or corrupted backtraces; no unsupported CPU decoding. - 100cmbacktrace-integration
Use when integrating, porting, configuring, or debugging CmBacktrace on Cortex-M faults, stack traces, firmware metadata, fault handlers, or crash logs - 100cuda-debugging
Use when debugging CUDA with cuda-gdb or Compute Sanitizer, reading GPU core dumps, using device printf, or triaging error codes 700, 701, 702, and 719. Not for performance: use cuda-profiling.