[esp8266] Decode crash handler PC and backtrace in logs (#16911)

This commit is contained in:
J. Nick Koston
2026-06-11 08:47:50 -05:00
committed by GitHub
parent a56b6d8993
commit 750cf1995b
2 changed files with 47 additions and 1 deletions

View File

@@ -492,6 +492,15 @@ def _parse_register(config, regex, line):
STACKTRACE_ESP8266_EXCEPTION_TYPE_RE = re.compile(r"[eE]xception \((\d+)\):")
STACKTRACE_ESP8266_PC_RE = re.compile(r"epc1=0x(4[0-9a-fA-F]{7})")
STACKTRACE_ESP8266_EXCVADDR_RE = re.compile(r"excvaddr=0x(4[0-9a-fA-F]{7})")
# Structured crash handler output (crash_handler.cpp) from a previous boot:
# PC: 0x40220060
# EXCVADDR: 0x0000008A
# BT0: 0x40212345
STACKTRACE_ESP8266_CRASH_PC_RE = re.compile(r".*PC\s*:\s*(?:0x)?(4[0-9a-fA-F]{7})")
STACKTRACE_ESP8266_CRASH_EXCVADDR_RE = re.compile(
r".*EXCVADDR\s*:\s*(?:0x)?(4[0-9a-fA-F]{7})"
)
STACKTRACE_ESP8266_CRASH_BT_RE = re.compile(r"BT\d+:\s*0x([0-9a-fA-F]{8})")
STACKTRACE_BAD_ALLOC_RE = re.compile(
r"^last failed alloc call: (4[0-9a-fA-F]{7})\((\d+)\)$"
)
@@ -508,10 +517,17 @@ def process_stacktrace(config, line, backtrace_state):
"Exception type: %s", ESP8266_EXCEPTION_CODES.get(code, "unknown")
)
# ESP8266 PC/EXCVADDR
# ESP8266 PC/EXCVADDR (legacy Arduino postmortem)
_parse_register(config, STACKTRACE_ESP8266_PC_RE, line)
_parse_register(config, STACKTRACE_ESP8266_EXCVADDR_RE, line)
# ESP8266 structured crash handler (crash_handler.cpp) from previous boot
_parse_register(config, STACKTRACE_ESP8266_CRASH_PC_RE, line)
_parse_register(config, STACKTRACE_ESP8266_CRASH_EXCVADDR_RE, line)
match = re.search(STACKTRACE_ESP8266_CRASH_BT_RE, line)
if match is not None:
_decode_pc(config, match.group(1))
# bad alloc
match = re.match(STACKTRACE_BAD_ALLOC_RE, line)
if match is not None:

View File

@@ -45,6 +45,36 @@ def test_process_stacktrace_esp8266_backtrace(
assert state is False
def test_process_stacktrace_esp8266_crash_handler(
setup_core: Path, mock_esp8266_decode_pc: Mock
) -> None:
"""Test process_stacktrace handles ESP8266 crash handler backtrace lines."""
from esphome.components.esp8266 import process_stacktrace
config = {"name": "test"}
# Simulate crash handler log lines as they appear from the API/serial
line_pc = "[E][esp8266:191]: PC: 0x40220060"
state = process_stacktrace(config, line_pc, False)
mock_esp8266_decode_pc.assert_called_once_with(config, "40220060")
assert state is False
mock_esp8266_decode_pc.reset_mock()
# Near-null data address (wild pointer) is not a code address, must be ignored
line_excvaddr = "[E][esp8266:193]: EXCVADDR: 0x0000008A"
state = process_stacktrace(config, line_excvaddr, False)
mock_esp8266_decode_pc.assert_not_called()
assert state is False
mock_esp8266_decode_pc.reset_mock()
line_bt0 = "[E][esp8266:196]: BT0: 0x40212345"
state = process_stacktrace(config, line_bt0, False)
mock_esp8266_decode_pc.assert_called_once_with(config, "40212345")
assert state is False
def test_process_stacktrace_esp32_backtrace(
setup_core: Path, mock_esp32_decode_pc: Mock
) -> None: