[nrf52] print line number after crash in logs (#14165)

This commit is contained in:
tomaszduda23
2026-02-21 14:16:20 -05:00
committed by GitHub
parent 6ff17fbf7c
commit 48ba007c22
3 changed files with 62 additions and 3 deletions
+16 -3
View File
@@ -431,6 +431,14 @@ def run_miniterm(config: ConfigType, port: str, args) -> int:
return 1
_LOGGER.info("Starting log output from %s with baud rate %s", port, baud_rate)
process_stacktrace = None
try:
module = importlib.import_module("esphome.components." + CORE.target_platform)
process_stacktrace = getattr(module, "process_stacktrace")
except AttributeError:
pass
backtrace_state = False
ser = serial.Serial()
ser.baudrate = baud_rate
@@ -472,9 +480,14 @@ def run_miniterm(config: ConfigType, port: str, args) -> int:
)
safe_print(parser.parse_line(line, time_str))
backtrace_state = platformio_api.process_stacktrace(
config, line, backtrace_state=backtrace_state
)
if process_stacktrace:
backtrace_state = process_stacktrace(
config, line, backtrace_state
)
else:
backtrace_state = platformio_api.process_stacktrace(
config, line, backtrace_state=backtrace_state
)
except serial.SerialException:
_LOGGER.error("Serial port closed!")
return 0
+40
View File
@@ -3,6 +3,8 @@ from __future__ import annotations
import asyncio
import logging
from pathlib import Path
import re
import subprocess
from esphome import pins
import esphome.codegen as cg
@@ -380,3 +382,41 @@ def show_logs(config: ConfigType, args, devices: list[str]) -> bool:
asyncio.run(logger_connect(address))
return True
return False
def _addr2line(addr2line: str, elf: Path, addr: str) -> str:
try:
result = subprocess.run(
[addr2line, "-e", elf, addr],
capture_output=True,
text=True,
check=True,
)
return result.stdout.strip().splitlines()[0]
except Exception as err: # pylint: disable=broad-except
_LOGGER.error("Running command failed: %s", err)
return ""
def process_stacktrace(config: ConfigType, line: str, backtrace_state: bool) -> bool:
if "Last crash:" in line:
return True
if backtrace_state:
match = re.search(r"PC=(0x[0-9a-fA-F]+)\s+LR=(0x[0-9a-fA-F]+)", line)
if match:
pc = match.group(1)
lr = match.group(2)
from esphome.analyze_memory.toolchain import find_tool
addr2line = find_tool("addr2line")
if addr2line is None:
return False
elf = CORE.relative_pioenvs_path(CORE.name, "firmware.elf")
if not elf.exists():
_LOGGER.warning("%s does not exists", elf)
return False
_LOGGER.error("=== CRASH ===")
_LOGGER.error("PC: %s", _addr2line(addr2line, elf, pc))
_LOGGER.error("LR: %s", _addr2line(addr2line, elf, lr))
return False
+6
View File
@@ -2951,6 +2951,7 @@ def test_run_miniterm_batches_lines_with_same_timestamp(
mock_serial = MockSerial([chunk, MOCK_SERIAL_END])
CORE.data[KEY_CORE] = {KEY_TARGET_PLATFORM: PLATFORM_ESP32}
config = {
CONF_LOGGER: {
CONF_BAUD_RATE: 115200,
@@ -2989,6 +2990,7 @@ def test_run_miniterm_different_chunks_different_timestamps(
mock_serial = MockSerial([chunk1, chunk2, MOCK_SERIAL_END])
CORE.data[KEY_CORE] = {KEY_TARGET_PLATFORM: PLATFORM_ESP32}
config = {
CONF_LOGGER: {
CONF_BAUD_RATE: 115200,
@@ -3019,6 +3021,7 @@ def test_run_miniterm_handles_split_lines() -> None:
mock_serial = MockSerial([chunk1, chunk2, MOCK_SERIAL_END])
CORE.data[KEY_CORE] = {KEY_TARGET_PLATFORM: PLATFORM_ESP32}
config = {
CONF_LOGGER: {
CONF_BAUD_RATE: 115200,
@@ -3057,6 +3060,7 @@ def test_run_miniterm_backtrace_state_maintained() -> None:
mock_serial = MockSerial([backtrace_chunk, MOCK_SERIAL_END])
CORE.data[KEY_CORE] = {KEY_TARGET_PLATFORM: PLATFORM_ESP32}
config = {
CONF_LOGGER: {
CONF_BAUD_RATE: 115200,
@@ -3122,6 +3126,7 @@ def test_run_miniterm_handles_empty_reads(
mock_serial = MockSerial([b"", chunk, b"", MOCK_SERIAL_END])
CORE.data[KEY_CORE] = {KEY_TARGET_PLATFORM: PLATFORM_ESP32}
config = {
CONF_LOGGER: {
CONF_BAUD_RATE: 115200,
@@ -3194,6 +3199,7 @@ def test_run_miniterm_buffer_limit_prevents_unbounded_growth() -> None:
mock_serial = MockSerial([large_data_no_newline, final_line, MOCK_SERIAL_END])
CORE.data[KEY_CORE] = {KEY_TARGET_PLATFORM: PLATFORM_ESP32}
config = {
CONF_LOGGER: {
CONF_BAUD_RATE: 115200,