panicdump
A Cortex-M fault can erase the register and reason context needed for diagnosis.
A retained-RAM library commits a fixed 192-byte CRC-protected dump and exports it for offline decoding.
Capture once; inspect after reset
panicdump is a retained-RAM crash-record library for bare-metal Cortex-M3/M4 systems, with host/mock testing and an offline Python decoder. Fault capture records a bounded CPU register set and a short stack slice into a fixed wire image.
The commit ordering first clears the magic, writes header/register/stack bytes, computes CRC with the CRC field treated as zero, writes CRC, and publishes final magic last. A reader accepts only a record with the supported header, architecture/reason, bounded stack length and matching CRC.
192 bytes with explicit offsets
| Offset | Size | Field | Role |
|---|---|---|---|
| 0 | 4 | Magic | Commit marker; written last |
| 4 | 2 | Version | Wire format v1 |
| 6 | 2 | Header size | 36 bytes |
| 8 | 4 | Total size | 192 bytes |
| 12 | 4 | Flags | Frame, PSP and stack validity bits |
| 16–31 | 16 | Architecture, reason, sequence, user tag | Context identifiers and application tag |
| 32 | 4 | CRC-32 | Whole image with this field treated as zero |
| 36 | 84 | Registers | 21 little-endian 32-bit values |
| 120 | 72 | Stack block | Captured SP, length and up to 64 data bytes |
The little-endian format gives a stable boundary between fault-time capture, retained storage, text export and host-side decode. CRC checks accidental corruption; it does not authenticate a record or prove its source.
The linker and startup code preserve the dump
Embedded integration places the dump in a .noinit NOLOAD section, after .bss and before the stack. Startup code must not clear that section. The application checks for a valid record very early on the next boot and can export or clear it.
Cortex-M integrations must set RAM bounds for the actual MCU. If a fault frame lies outside the configured retained window, panicdump records safe registers and marks the frame invalid rather than dereferencing that pointer. Incorrect RAM bounds can yield no useful stack slice or risk a nested fault.
Move bytes out before analyzing registers
The API can export the retained wire image as hex text through a caller-provided character callback, or combine early-boot validity check and export. Python tooling decodes binary or hex captures, emits JSON and can verify the record.
python3 tools/decode_panicdump.py dump.bin
python3 tools/decode_panicdump.py --hex uart_capture.txt
python3 tools/decode_panicdump.py --json dump.bin
python3 tools/decode_panicdump.py --verify dump.binReason tags can be supplied by a bounded string wrapper or as a numeric tag. The record stores a user tag and a bounded reason code rather than an arbitrary string payload.
Format and decoder checks have separate roles
The repository includes a host/mock port, native C tests, Python format/CLI tests, fixed binary and text vectors, and package-consumer checks. Its current README reports a GitHub Actions run covering host, sanitizer, static-analysis, package, Python decoder and ARM verification gates. This is repository-reported CI evidence, not a statement that the current physical target setup was tested here.
Retained crash evidence, not a complete debugger
- Current target scope is bare-metal Cortex-M3/M4 non-FPU; Cortex-M0/M0+, M4F/M7 FPU builds, RTOS awareness and other architectures are unsupported.
- No flash backend, stack unwinding, symbol resolution, multiple dump slots, encryption or compression.
- Capture is best effort; invalid frames are marked rather than blindly dereferenced.
- RAM window, linker script, vector table, fault enables and startup code must be integrated for the exact board.
- CRC-32 detects accidental corruption only; the format is not authenticated.
- Host/mock tests and CI gates do not establish real board fault capture or every startup/linker interaction.