From 42ac8c705add50da4403291eab5a4f4f46c7b25a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 11 Mar 2026 14:02:28 -1000 Subject: [PATCH] Guard crash handler behind USE_ESP32_CRASH_HANDLER define Arduino framework already wraps esp_panic_handler for its own backtrace handler, causing a linker conflict. Only enable our crash handler when using ESP-IDF framework by gating behind USE_ESP32_CRASH_HANDLER define (set via cg.add_define). Co-Authored-By: J. Nick Koston --- esphome/components/api/api_connection.h | 4 ++-- esphome/components/esp32/__init__.py | 6 +++++- esphome/components/esp32/core.cpp | 4 +++- esphome/components/esp32/crash_handler.cpp | 4 ++++ esphome/components/esp32/crash_handler.h | 4 ++-- esphome/components/logger/logger_esp32.cpp | 2 ++ esphome/core/defines.h | 1 + 7 files changed, 19 insertions(+), 6 deletions(-) diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 6af142fecbc..60cc3e91b11 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -14,7 +14,7 @@ #include "api_server.h" #include "esphome/core/application.h" #include "esphome/core/component.h" -#ifdef USE_ESP32 +#ifdef USE_ESP32_CRASH_HANDLER #include "esphome/components/esp32/crash_handler.h" #endif #include "esphome/core/entity_base.h" @@ -238,7 +238,7 @@ class APIConnection final : public APIServerConnectionBase { this->flags_.log_subscription = msg.level; if (msg.dump_config) App.schedule_dump_config(); -#ifdef USE_ESP32 +#ifdef USE_ESP32_CRASH_HANDLER esp32::crash_handler_log(); #endif } diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 630db2271b4..475de6aa3e4 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -1442,7 +1442,11 @@ async def to_code(config): cg.add_build_flag("-DUSE_ESP32") cg.add_define("USE_NATIVE_64BIT_TIME") cg.add_build_flag("-Wl,-z,noexecstack") - cg.add_build_flag("-Wl,--wrap=esp_panic_handler") + # Arduino already wraps esp_panic_handler for its own backtrace handler, + # so only add our wrap when using ESP-IDF framework to avoid linker conflicts. + if conf[CONF_TYPE] == FRAMEWORK_ESP_IDF: + cg.add_build_flag("-Wl,--wrap=esp_panic_handler") + cg.add_define("USE_ESP32_CRASH_HANDLER") cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) variant = config[CONF_VARIANT] cg.add_build_flag(f"-DUSE_ESP32_VARIANT_{variant}") diff --git a/esphome/components/esp32/core.cpp b/esphome/components/esp32/core.cpp index 7b13f4b4a35..cba25bca2b2 100644 --- a/esphome/components/esp32/core.cpp +++ b/esphome/components/esp32/core.cpp @@ -1,7 +1,7 @@ #ifdef USE_ESP32 -#include "crash_handler.h" #include "esphome/core/defines.h" +#include "crash_handler.h" #include "esphome/core/hal.h" #include "esphome/core/helpers.h" #include "preferences.h" @@ -37,8 +37,10 @@ void arch_restart() { } void arch_init() { +#ifdef USE_ESP32_CRASH_HANDLER // Read crash data from previous boot before anything else esp32::crash_handler_read_and_clear(); +#endif // Enable the task watchdog only on the loop task (from which we're currently running) esp_task_wdt_add(nullptr); diff --git a/esphome/components/esp32/crash_handler.cpp b/esphome/components/esp32/crash_handler.cpp index 1aa4f651423..ecf30d78781 100644 --- a/esphome/components/esp32/crash_handler.cpp +++ b/esphome/components/esp32/crash_handler.cpp @@ -1,5 +1,8 @@ #ifdef USE_ESP32 +#include "esphome/core/defines.h" +#ifdef USE_ESP32_CRASH_HANDLER + #include "crash_handler.h" #include "esphome/core/log.h" @@ -348,4 +351,5 @@ void IRAM_ATTR __wrap_esp_panic_handler(panic_info_t *info) { // NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp,readability-identifier-naming) } // extern "C" +#endif // USE_ESP32_CRASH_HANDLER #endif // USE_ESP32 diff --git a/esphome/components/esp32/crash_handler.h b/esphome/components/esp32/crash_handler.h index c2c42c4ffd2..97a4d4e1162 100644 --- a/esphome/components/esp32/crash_handler.h +++ b/esphome/components/esp32/crash_handler.h @@ -1,6 +1,6 @@ #pragma once -#ifdef USE_ESP32 +#ifdef USE_ESP32_CRASH_HANDLER namespace esphome::esp32 { @@ -15,4 +15,4 @@ bool crash_handler_has_data(); } // namespace esphome::esp32 -#endif // USE_ESP32 +#endif // USE_ESP32_CRASH_HANDLER diff --git a/esphome/components/logger/logger_esp32.cpp b/esphome/components/logger/logger_esp32.cpp index 53768b37969..f5bf7822899 100644 --- a/esphome/components/logger/logger_esp32.cpp +++ b/esphome/components/logger/logger_esp32.cpp @@ -118,7 +118,9 @@ void Logger::pre_setup() { esp_log_set_vprintf(esp_idf_log_vprintf_); ESP_LOGI(TAG, "Log initialized"); +#ifdef USE_ESP32_CRASH_HANDLER esp32::crash_handler_log(); +#endif } void HOT Logger::write_msg_(const char *msg, uint16_t len) { diff --git a/esphome/core/defines.h b/esphome/core/defines.h index cec77fe2e27..a33f10cb9c0 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -195,6 +195,7 @@ // ESP32-specific feature flags #ifdef USE_ESP32 +#define USE_ESP32_CRASH_HANDLER #define USE_MQTT_IDF_ENQUEUE #define USE_ESPHOME_TASK_LOG_BUFFER #define USE_OTA_ROLLBACK