mirror of
https://github.com/esphome/esphome.git
synced 2026-09-17 10:08:40 +00:00
Address review feedback: RP2350 compat, noreturn, addr2line hint
- Add #if defined(PICO_RP2350) for SRAM end (520KB vs 264KB) so stack scanning works on both RP2040 and RP2350 - Widen flash range check to 4MB for RP2350 - Add __attribute__((noreturn)) to hard_fault_handler_c - Mark exc_return parameter as unused via /*exc_return*/ - Build addr2line hint line with all addresses (PC, LR, and BT*) so users can copy-paste a single command for full decode
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#include "crash_handler.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <hardware/structs/watchdog.h>
|
||||
#include <hardware/watchdog.h>
|
||||
|
||||
@@ -24,13 +25,18 @@ static constexpr uint32_t CRASH_MAGIC = 0xDEADBEEF;
|
||||
// [4..7] = up to 4 additional code addresses found by scanning the stack
|
||||
// (return addresses from callers, giving a deeper backtrace)
|
||||
|
||||
// RP2040 flash is mapped at 0x10000000 with up to 16MB address space.
|
||||
// We use 2MB as the upper bound — large enough for any typical ESPHome firmware
|
||||
// while keeping false positives low during stack scanning. Wider ranges would
|
||||
// match more stale data on the stack that happens to look like code addresses.
|
||||
// Flash is mapped at 0x10000000. RP2040 supports up to 16MB, RP2350 up to 32MB.
|
||||
// We use a conservative upper bound to keep false positives low during stack scanning.
|
||||
// Wider ranges would match more stale data on the stack that happens to look like code addresses.
|
||||
#if defined(PICO_RP2350)
|
||||
static constexpr uint32_t FLASH_END = 0x10400000; // 4MB — RP2350 typical max
|
||||
#else
|
||||
static constexpr uint32_t FLASH_END = 0x10200000; // 2MB — RP2040 typical max
|
||||
#endif
|
||||
|
||||
static inline bool is_code_addr(uint32_t val) {
|
||||
uint32_t cleared = val & ~1u; // Clear Thumb bit
|
||||
return cleared >= 0x10000000 && cleared < 0x10200000;
|
||||
return cleared >= 0x10000000 && cleared < FLASH_END;
|
||||
}
|
||||
|
||||
static constexpr size_t MAX_BACKTRACE = 4;
|
||||
@@ -85,7 +91,14 @@ void crash_handler_log() {
|
||||
for (uint8_t i = 0; i < s_crash_data.backtrace_count; i++) {
|
||||
ESP_LOGE(TAG, " BT%d: 0x%08X (stack backtrace)", i, s_crash_data.backtrace[i]);
|
||||
}
|
||||
ESP_LOGE(TAG, "Use addr2line -e firmware.elf 0x%08X 0x%08X to decode", s_crash_data.pc, s_crash_data.lr);
|
||||
// Build addr2line hint with all captured addresses for easy copy-paste
|
||||
char hint[160];
|
||||
int pos = snprintf(hint, sizeof(hint), "Use: addr2line -pfiaC -e firmware.elf 0x%08" PRIX32 " 0x%08" PRIX32,
|
||||
s_crash_data.pc, s_crash_data.lr);
|
||||
for (uint8_t i = 0; i < s_crash_data.backtrace_count && pos < (int) sizeof(hint) - 12; i++) {
|
||||
pos += snprintf(hint + pos, sizeof(hint) - pos, " 0x%08" PRIX32, s_crash_data.backtrace[i]);
|
||||
}
|
||||
ESP_LOGE(TAG, "%s", hint);
|
||||
}
|
||||
|
||||
} // namespace esphome::rp2040
|
||||
@@ -98,7 +111,7 @@ void crash_handler_log() {
|
||||
// (which survive watchdog reboot), then trigger a reboot.
|
||||
|
||||
// C handler called from the asm wrapper with the exception frame pointer.
|
||||
static void __attribute__((used)) hard_fault_handler_c(uint32_t *frame, uint32_t exc_return) {
|
||||
static void __attribute__((used, noreturn)) hard_fault_handler_c(uint32_t *frame, uint32_t /*exc_return*/) {
|
||||
// watchdog_reboot() overwrites scratch[4]-[7], so we must call it first
|
||||
// then write ALL our data after. The 10ms timeout gives us plenty of time.
|
||||
watchdog_reboot(0, 0, 10);
|
||||
@@ -113,8 +126,12 @@ static void __attribute__((used)) hard_fault_handler_c(uint32_t *frame, uint32_t
|
||||
// The exception frame is 8 words (32 bytes) at 'frame'. The pre-fault
|
||||
// stack starts at frame+8. Walk up to 64 words looking for return addresses.
|
||||
uint32_t *scan_start = frame + 8; // Past exception frame
|
||||
// RP2040 RAM ends at 0x20042000 (264KB SRAM)
|
||||
uint32_t *stack_top = (uint32_t *) 0x20042000;
|
||||
// SRAM end address differs by chip variant
|
||||
#if defined(PICO_RP2350)
|
||||
uint32_t *stack_top = (uint32_t *) 0x20082000; // RP2350: 520KB SRAM
|
||||
#else
|
||||
uint32_t *stack_top = (uint32_t *) 0x20042000; // RP2040: 264KB SRAM
|
||||
#endif
|
||||
uint32_t bt_count = 0;
|
||||
|
||||
for (uint32_t *p = scan_start; p < stack_top && p < scan_start + 64 && bt_count < MAX_BACKTRACE; p++) {
|
||||
|
||||
Reference in New Issue
Block a user