Stack scanning captures any value that looks like a code address, which
includes false positives. At log time (flash cache is up), validate each
address by checking if the preceding instruction is a JAL/JALR with
rd=ra. This filters spurious entries like FreeRTOS internals that happen
to be on the stack but aren't part of the actual call chain.
Co-Authored-By: J. Nick Koston <nick@koston.org>
Version first ensures future firmware can always identify the struct
layout without depending on any other field positions.
Co-Authored-By: J. Nick Koston <nick@koston.org>
Allows future firmware to detect and skip incompatible crash data
layouts. Placed alongside backtrace_count to avoid adding padding.
Co-Authored-By: J. Nick Koston <nick@koston.org>
Moving backtrace_count before the variable-length backtrace array
ensures magic, pc, and count are at fixed offsets regardless of
MAX_BACKTRACE value. This makes the .noinit data readable across
firmware versions that may change the max backtrace depth.
Co-Authored-By: J. Nick Koston <nick@koston.org>
Saves 76 bytes of RAM by removing the validated BSS copy and reading
directly from the .noinit struct after magic validation. A single bool
tracks whether valid crash data was found this boot.
Co-Authored-By: J. Nick Koston <nick@koston.org>
8 frames was cutting off useful call stack information. 16 frames
costs an additional 32 bytes of .noinit RAM and covers typical
ESPHome call chains which can be 10-12 frames deep.
The esphome logs command via API wasn't running process_stacktrace
on received log lines, so crash handler backtrace addresses were
displayed but not decoded with addr2line.
- Make s_raw_crash_data static with inline .noinit definition (no extern needed)
- Remove valid=false clearing from crash_handler_log() so both serial (boot)
and API (subscribe) paths can emit the crash data
- Clear valid flag after logging to prevent re-logging on API reconnects
- Cache esp_cpu_process_stack_pc result to avoid redundant call
- Remove unused <cstdint> include from header
When an ESP32 crashes, the backtrace is printed to UART and lost.
Users without a serial cable never see this diagnostic information.
This adds a crash handler that:
- Intercepts esp_panic_handler() via --wrap linker flag
- Captures the faulting PC and backtrace into .noinit memory
- Supports both Xtensa (ESP32/S2/S3) and RISC-V (C3/C6/H2/C2)
- Logs crash data at boot via ESP_LOGE (serial output)
- Re-logs when HA subscribes to logs (visible in HA log viewer)
- Adds CLI stacktrace decoding for the new log format
Co-authored-by: Jonathan Swoboda <swoboda1337@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>