98static uint8_t IRAM_ATTR capture_riscv_backtrace(RvExcFrame *frame,
uint32_t *out, uint8_t max, uint8_t *reg_count) {
164static const char *
const TAG =
"esp32.crash";
174static uint32_t s_current_build_time =
static_cast<uint32_t>(ESPHOME_BUILD_TIME);
177 if (s_raw_crash_data.magic == CRASH_MAGIC && s_raw_crash_data.version == CRASH_DATA_VERSION) {
178 s_crash_data_valid =
true;
180 if (s_raw_crash_data.backtrace_count > MAX_BACKTRACE)
181 s_raw_crash_data.backtrace_count = MAX_BACKTRACE;
182 if (s_raw_crash_data.reg_frame_count > s_raw_crash_data.backtrace_count)
183 s_raw_crash_data.reg_frame_count = s_raw_crash_data.backtrace_count;
184 if (s_raw_crash_data.exception > 4)
185 s_raw_crash_data.exception = 4;
186 if (s_raw_crash_data.pseudo_excause > 1)
187 s_raw_crash_data.pseudo_excause = 0;
188 if (s_raw_crash_data.crashed_core >= SOC_CPU_CORES_NUM)
189 s_raw_crash_data.crashed_core = 0;
190#if SOC_CPU_CORES_NUM > 1
191 if (s_raw_crash_data.other_backtrace_count > MAX_BACKTRACE)
192 s_raw_crash_data.other_backtrace_count = MAX_BACKTRACE;
193 if (s_raw_crash_data.other_reg_frame_count > s_raw_crash_data.other_backtrace_count)
194 s_raw_crash_data.other_reg_frame_count = s_raw_crash_data.other_backtrace_count;
207 s_raw_crash_data.magic = 0;
211static bool cause_slot_was_written() {
212#if CONFIG_IDF_TARGET_ARCH_XTENSA
213 return s_raw_crash_data.cause < XTENSA_EXCCAUSE_COUNT;
215 return s_raw_crash_data.cause < RISCV_EXCEPTION_CAUSE_COUNT;
222static const char *get_exception_reason() {
223 uint8_t exception = s_raw_crash_data.exception;
224 if (exception == PANIC_EXCEPTION_ABORT || exception == PANIC_EXCEPTION_TWDT) {
228 if (!cause_slot_was_written()) {
232#if CONFIG_IDF_TARGET_ARCH_XTENSA
233 if (s_raw_crash_data.pseudo_excause) {
236 static const char *
const PSEUDO_REASON[] = {
238 "Unhandled debug exception",
240 "Unhandled kernel exception",
241 "Coprocessor exception",
242 "Interrupt wdt timeout on CPU0",
243 "Interrupt wdt timeout on CPU1",
246 uint32_t cause = s_raw_crash_data.cause;
247 if (cause <
sizeof(PSEUDO_REASON) /
sizeof(PSEUDO_REASON[0]))
248 return PSEUDO_REASON[cause];
249 return PSEUDO_REASON[0];
252 static const char *
const REASON[] = {
253 "IllegalInstruction",
255 "InstructionFetchError",
259 "IntegerDivideByZero",
262 "LoadStoreAlignment",
266 "LoadStorePIFDataError",
268 "LoadStorePIFAddrError",
271 "InstFetchPrivilege",
273 "InstrFetchProhibited",
278 "LoadStoreTLBMultihit",
279 "LoadStorePrivilege",
294 uint32_t cause = s_raw_crash_data.cause;
295 if (cause <
sizeof(REASON) /
sizeof(REASON[0]) && REASON[cause] !=
nullptr)
296 return REASON[cause];
297#elif CONFIG_IDF_TARGET_ARCH_RISCV
301 if (s_raw_crash_data.pseudo_excause)
303 static const char *
const REASON[] = {
304 "Instruction address misaligned",
305 "Instruction access fault",
306 "Illegal instruction",
308 "Load address misaligned",
310 "Store address misaligned",
311 "Store access fault",
312 "Environment call from U-mode",
313 "Environment call from S-mode",
315 "Environment call from M-mode",
316 "Instruction page fault",
321 uint32_t cause = s_raw_crash_data.cause;
322 if (cause <
sizeof(REASON) /
sizeof(REASON[0]) && REASON[cause] !=
nullptr)
323 return REASON[cause];
329static const char *get_exception_type() {
330 static const char *
const TYPES[] = {
337 uint8_t exc = s_raw_crash_data.exception;
338 if (exc <
sizeof(TYPES) /
sizeof(TYPES[0]))
344static void log_backtrace(
const uint32_t *addrs, uint8_t count, uint8_t reg_frame_count) {
346 for (uint8_t i = 0; i < count; i++) {
348#if CONFIG_IDF_TARGET_ARCH_RISCV
349 if (i >= reg_frame_count && !is_return_addr(addr))
351 const char *source = (i < reg_frame_count) ?
"backtrace" :
"stack scan";
353 const char *source =
"backtrace";
355 ESP_LOGE(TAG,
" BT%d: 0x%08" PRIX32
" (%s)", bt_num++, addr, source);
360static int append_addrs_to_hint(
char *buf,
int size,
int pos,
const uint32_t *addrs, uint8_t count,
361 uint8_t reg_frame_count) {
362 for (uint8_t i = 0; i < count &&
pos <
size - 12; i++) {
364#if CONFIG_IDF_TARGET_ARCH_RISCV
365 if (i >= reg_frame_count && !is_return_addr(addr))
368 pos += snprintf(buf + pos, size - pos,
" 0x%08" PRIX32, addr);
376#if CONFIG_IDF_TARGET_ARCH_XTENSA
377static const char *
const FAULT_ADDR_REG =
"EXCVADDR";
378static const char *
const FAULT_ADDR_REG_LOWER =
"excvaddr";
379#elif CONFIG_IDF_TARGET_ARCH_RISCV
380static const char *
const FAULT_ADDR_REG =
"MTVAL";
381static const char *
const FAULT_ADDR_REG_LOWER =
"mtval";
386static bool has_fault_addr() {
387 return s_raw_crash_data.exception == PANIC_EXCEPTION_FAULT && !s_raw_crash_data.pseudo_excause &&
388 cause_slot_was_written();
398static uint8_t log_foreign_backtrace(
const uint32_t *addrs, uint8_t count, uint8_t bt_num) {
399 for (uint8_t i = 0; i < count; i++) {
400 ESP_LOGE(TAG,
" bt%d: 0x%08" PRIX32, bt_num++, addrs[i]);
405static void log_foreign_addresses() {
406 ESP_LOGE(TAG,
" Captured by a different firmware build; addresses belong to that build's ELF");
407 ESP_LOGE(TAG,
" pc: 0x%08" PRIX32, s_raw_crash_data.pc);
408 if (has_fault_addr()) {
409 ESP_LOGE(TAG,
" %s: 0x%08" PRIX32, FAULT_ADDR_REG_LOWER, s_raw_crash_data.fault_addr);
411 uint8_t bt_num = log_foreign_backtrace(s_raw_crash_data.backtrace, s_raw_crash_data.backtrace_count, 0);
412#if SOC_CPU_CORES_NUM > 1
413 if (s_raw_crash_data.other_backtrace_count > 0) {
415 ESP_LOGE(TAG,
" other core (%d):", 1 - s_raw_crash_data.crashed_core);
416 log_foreign_backtrace(s_raw_crash_data.other_backtrace, s_raw_crash_data.other_backtrace_count, bt_num);
429 if (!s_crash_data_valid)
432 ESP_LOGE(TAG,
"*** CRASH DETECTED ON PREVIOUS BOOT ***");
433 const char *reason = get_exception_reason();
434 if (reason !=
nullptr) {
435 ESP_LOGE(TAG,
" Reason: %s - %s (cause %" PRIu32
")", get_exception_type(), reason, s_raw_crash_data.cause);
437 ESP_LOGE(TAG,
" Reason: %s", get_exception_type());
439 ESP_LOGE(TAG,
" Crashed core: %d", s_raw_crash_data.crashed_core);
440 if (s_raw_crash_data.build_time != s_current_build_time) {
443 log_foreign_addresses();
446 ESP_LOGE(TAG,
" PC: 0x%08" PRIX32
" (fault location)", s_raw_crash_data.pc);
449 if (has_fault_addr()) {
450 ESP_LOGE(TAG,
" %s: 0x%08" PRIX32
" (faulting address)", FAULT_ADDR_REG, s_raw_crash_data.fault_addr);
452 log_backtrace(s_raw_crash_data.backtrace, s_raw_crash_data.backtrace_count, s_raw_crash_data.reg_frame_count);
454#if SOC_CPU_CORES_NUM > 1
455 if (s_raw_crash_data.other_backtrace_count > 0) {
456 int other_core = 1 - s_raw_crash_data.crashed_core;
457 ESP_LOGE(TAG,
" Other core (%d) backtrace:", other_core);
458 log_backtrace(s_raw_crash_data.other_backtrace, s_raw_crash_data.other_backtrace_count,
459 s_raw_crash_data.other_reg_frame_count);
466 static const char *
const ADDR2LINE_CMD =
"addr2line -pfiaC -e firmware.elf";
468 int pos = snprintf(hint,
sizeof(hint),
"Use: %s 0x%08" PRIX32, ADDR2LINE_CMD, s_raw_crash_data.pc);
469 append_addrs_to_hint(hint,
sizeof(hint),
pos, s_raw_crash_data.backtrace, s_raw_crash_data.backtrace_count,
470 s_raw_crash_data.reg_frame_count);
471 ESP_LOGE(TAG,
"%s", hint);
472#if SOC_CPU_CORES_NUM > 1
473 if (s_raw_crash_data.other_backtrace_count > 0) {
474 pos = snprintf(hint,
sizeof(hint),
"Other core: %s", ADDR2LINE_CMD);
475 append_addrs_to_hint(hint,
sizeof(hint),
pos, s_raw_crash_data.other_backtrace,
476 s_raw_crash_data.other_backtrace_count, s_raw_crash_data.other_reg_frame_count);
477 ESP_LOGE(TAG,
"%s", hint);
499 s_raw_crash_data.pc = (
uint32_t) info->addr;
500 s_raw_crash_data.backtrace_count = 0;
501 s_raw_crash_data.reg_frame_count = 0;
502 s_raw_crash_data.exception = (uint8_t) info->exception;
503 s_raw_crash_data.pseudo_excause = info->pseudo_excause ? 1 : 0;
504 s_raw_crash_data.crashed_core = (uint8_t) info->core;
510 bool is_twdt = &g_twdt_isr !=
nullptr && g_twdt_isr;
511 s_raw_crash_data.exception = (uint8_t) (is_twdt ? PANIC_EXCEPTION_TWDT : PANIC_EXCEPTION_ABORT);
514 s_raw_crash_data.cause = 0;
515 s_raw_crash_data.fault_addr = 0;
520 s_raw_crash_data.build_time = esphome::esp32::s_current_build_time;
521#if SOC_CPU_CORES_NUM > 1
522 s_raw_crash_data.other_backtrace_count = 0;
523 s_raw_crash_data.other_reg_frame_count = 0;
526#if CONFIG_IDF_TARGET_ARCH_XTENSA
528 if (info->frame !=
nullptr) {
529 auto *xt_frame = (XtExcFrame *) info->frame;
530 if (!g_panic_abort) {
533 s_raw_crash_data.cause = xt_frame->exccause;
534 s_raw_crash_data.fault_addr = xt_frame->excvaddr;
536 s_raw_crash_data.backtrace_count = walk_xtensa_backtrace(xt_frame, s_raw_crash_data.backtrace, MAX_BACKTRACE);
539#if SOC_CPU_CORES_NUM > 1
543 if (info->core >= 0 && info->core < SOC_CPU_CORES_NUM) {
544 int other_core = 1 - info->core;
545 auto *other_frame = (XtExcFrame *) g_exc_frames[other_core];
546 if (other_frame !=
nullptr) {
547 s_raw_crash_data.other_backtrace_count =
548 walk_xtensa_backtrace(other_frame, s_raw_crash_data.other_backtrace, MAX_BACKTRACE);
553#elif CONFIG_IDF_TARGET_ARCH_RISCV
555 if (info->frame !=
nullptr) {
556 auto *rv_frame = (RvExcFrame *) info->frame;
557 if (!g_panic_abort) {
559 s_raw_crash_data.cause = rv_frame->mcause;
560 s_raw_crash_data.fault_addr = rv_frame->mtval;
562 s_raw_crash_data.backtrace_count =
563 capture_riscv_backtrace(rv_frame, s_raw_crash_data.backtrace, MAX_BACKTRACE, &s_raw_crash_data.reg_frame_count);
566#if SOC_CPU_CORES_NUM > 1
568 if (info->core >= 0 && info->core < SOC_CPU_CORES_NUM) {
569 int other_core = 1 - info->core;
570 auto *other_frame = (RvExcFrame *) g_exc_frames[other_core];
571 if (other_frame !=
nullptr) {
572 s_raw_crash_data.other_backtrace_count = capture_riscv_backtrace(
573 other_frame, s_raw_crash_data.other_backtrace, MAX_BACKTRACE, &s_raw_crash_data.other_reg_frame_count);
580 s_raw_crash_data.version = CRASH_DATA_VERSION;
581 s_raw_crash_data.magic = CRASH_MAGIC;