98static uint8_t IRAM_ATTR capture_riscv_backtrace(RvExcFrame *frame,
uint32_t *out, uint8_t max, uint8_t *reg_count) {
155static const char *
const TAG =
"esp32.crash";
165static uint32_t s_current_build_time =
static_cast<uint32_t>(ESPHOME_BUILD_TIME);
168 if (s_raw_crash_data.magic == CRASH_MAGIC && s_raw_crash_data.version == CRASH_DATA_VERSION) {
169 s_crash_data_valid =
true;
171 if (s_raw_crash_data.backtrace_count > MAX_BACKTRACE)
172 s_raw_crash_data.backtrace_count = MAX_BACKTRACE;
173 if (s_raw_crash_data.reg_frame_count > s_raw_crash_data.backtrace_count)
174 s_raw_crash_data.reg_frame_count = s_raw_crash_data.backtrace_count;
175 if (s_raw_crash_data.exception > 4)
176 s_raw_crash_data.exception = 4;
177 if (s_raw_crash_data.pseudo_excause > 1)
178 s_raw_crash_data.pseudo_excause = 0;
179 if (s_raw_crash_data.crashed_core >= SOC_CPU_CORES_NUM)
180 s_raw_crash_data.crashed_core = 0;
181#if SOC_CPU_CORES_NUM > 1
182 if (s_raw_crash_data.other_backtrace_count > MAX_BACKTRACE)
183 s_raw_crash_data.other_backtrace_count = MAX_BACKTRACE;
184 if (s_raw_crash_data.other_reg_frame_count > s_raw_crash_data.other_backtrace_count)
185 s_raw_crash_data.other_reg_frame_count = s_raw_crash_data.other_backtrace_count;
198 s_raw_crash_data.magic = 0;
204static const char *get_exception_reason() {
205#if CONFIG_IDF_TARGET_ARCH_XTENSA
206 if (s_raw_crash_data.pseudo_excause) {
209 static const char *
const PSEUDO_REASON[] = {
211 "Unhandled debug exception",
213 "Unhandled kernel exception",
214 "Coprocessor exception",
215 "Interrupt wdt timeout on CPU0",
216 "Interrupt wdt timeout on CPU1",
219 uint32_t cause = s_raw_crash_data.cause;
220 if (cause <
sizeof(PSEUDO_REASON) /
sizeof(PSEUDO_REASON[0]))
221 return PSEUDO_REASON[cause];
222 return PSEUDO_REASON[0];
225 static const char *
const REASON[] = {
226 "IllegalInstruction",
228 "InstructionFetchError",
232 "IntegerDivideByZero",
235 "LoadStoreAlignment",
239 "LoadStorePIFDataError",
241 "LoadStorePIFAddrError",
244 "InstFetchPrivilege",
246 "InstrFetchProhibited",
251 "LoadStoreTLBMultihit",
252 "LoadStorePrivilege",
267 uint32_t cause = s_raw_crash_data.cause;
268 if (cause <
sizeof(REASON) /
sizeof(REASON[0]) && REASON[cause] !=
nullptr)
269 return REASON[cause];
270#elif CONFIG_IDF_TARGET_ARCH_RISCV
274 if (s_raw_crash_data.pseudo_excause)
276 static const char *
const REASON[] = {
277 "Instruction address misaligned",
278 "Instruction access fault",
279 "Illegal instruction",
281 "Load address misaligned",
283 "Store address misaligned",
284 "Store access fault",
285 "Environment call from U-mode",
286 "Environment call from S-mode",
288 "Environment call from M-mode",
289 "Instruction page fault",
294 uint32_t cause = s_raw_crash_data.cause;
295 if (cause <
sizeof(REASON) /
sizeof(REASON[0]) && REASON[cause] !=
nullptr)
296 return REASON[cause];
302static const char *get_exception_type() {
303 static const char *
const TYPES[] = {
310 uint8_t exc = s_raw_crash_data.exception;
311 if (exc <
sizeof(TYPES) /
sizeof(TYPES[0]))
317static void log_backtrace(
const uint32_t *addrs, uint8_t count, uint8_t reg_frame_count) {
319 for (uint8_t i = 0; i < count; i++) {
321#if CONFIG_IDF_TARGET_ARCH_RISCV
322 if (i >= reg_frame_count && !is_return_addr(addr))
324 const char *source = (i < reg_frame_count) ?
"backtrace" :
"stack scan";
326 const char *source =
"backtrace";
328 ESP_LOGE(TAG,
" BT%d: 0x%08" PRIX32
" (%s)", bt_num++, addr, source);
333static int append_addrs_to_hint(
char *buf,
int size,
int pos,
const uint32_t *addrs, uint8_t count,
334 uint8_t reg_frame_count) {
335 for (uint8_t i = 0; i < count &&
pos <
size - 12; i++) {
337#if CONFIG_IDF_TARGET_ARCH_RISCV
338 if (i >= reg_frame_count && !is_return_addr(addr))
341 pos += snprintf(buf + pos, size - pos,
" 0x%08" PRIX32, addr);
349#if CONFIG_IDF_TARGET_ARCH_XTENSA
350static const char *
const FAULT_ADDR_REG =
"EXCVADDR";
351static const char *
const FAULT_ADDR_REG_LOWER =
"excvaddr";
352#elif CONFIG_IDF_TARGET_ARCH_RISCV
353static const char *
const FAULT_ADDR_REG =
"MTVAL";
354static const char *
const FAULT_ADDR_REG_LOWER =
"mtval";
359static bool has_fault_addr() {
360 return s_raw_crash_data.exception == PANIC_EXCEPTION_FAULT && !s_raw_crash_data.pseudo_excause;
370static uint8_t log_foreign_backtrace(
const uint32_t *addrs, uint8_t count, uint8_t bt_num) {
371 for (uint8_t i = 0; i < count; i++) {
372 ESP_LOGE(TAG,
" bt%d: 0x%08" PRIX32, bt_num++, addrs[i]);
377static void log_foreign_addresses() {
378 ESP_LOGE(TAG,
" Captured by a different firmware build; addresses belong to that build's ELF");
379 ESP_LOGE(TAG,
" pc: 0x%08" PRIX32, s_raw_crash_data.pc);
380 if (has_fault_addr()) {
381 ESP_LOGE(TAG,
" %s: 0x%08" PRIX32, FAULT_ADDR_REG_LOWER, s_raw_crash_data.fault_addr);
383 uint8_t bt_num = log_foreign_backtrace(s_raw_crash_data.backtrace, s_raw_crash_data.backtrace_count, 0);
384#if SOC_CPU_CORES_NUM > 1
385 if (s_raw_crash_data.other_backtrace_count > 0) {
387 ESP_LOGE(TAG,
" other core (%d):", 1 - s_raw_crash_data.crashed_core);
388 log_foreign_backtrace(s_raw_crash_data.other_backtrace, s_raw_crash_data.other_backtrace_count, bt_num);
401 if (!s_crash_data_valid)
404 ESP_LOGE(TAG,
"*** CRASH DETECTED ON PREVIOUS BOOT ***");
405 const char *reason = get_exception_reason();
406 if (reason !=
nullptr) {
407 ESP_LOGE(TAG,
" Reason: %s - %s (cause %" PRIu32
")", get_exception_type(), reason, s_raw_crash_data.cause);
409 ESP_LOGE(TAG,
" Reason: %s", get_exception_type());
411 ESP_LOGE(TAG,
" Crashed core: %d", s_raw_crash_data.crashed_core);
412 if (s_raw_crash_data.build_time != s_current_build_time) {
415 log_foreign_addresses();
418 ESP_LOGE(TAG,
" PC: 0x%08" PRIX32
" (fault location)", s_raw_crash_data.pc);
421 if (has_fault_addr()) {
422 ESP_LOGE(TAG,
" %s: 0x%08" PRIX32
" (faulting address)", FAULT_ADDR_REG, s_raw_crash_data.fault_addr);
424 log_backtrace(s_raw_crash_data.backtrace, s_raw_crash_data.backtrace_count, s_raw_crash_data.reg_frame_count);
426#if SOC_CPU_CORES_NUM > 1
427 if (s_raw_crash_data.other_backtrace_count > 0) {
428 int other_core = 1 - s_raw_crash_data.crashed_core;
429 ESP_LOGE(TAG,
" Other core (%d) backtrace:", other_core);
430 log_backtrace(s_raw_crash_data.other_backtrace, s_raw_crash_data.other_backtrace_count,
431 s_raw_crash_data.other_reg_frame_count);
438 static const char *
const ADDR2LINE_CMD =
"addr2line -pfiaC -e firmware.elf";
440 int pos = snprintf(hint,
sizeof(hint),
"Use: %s 0x%08" PRIX32, ADDR2LINE_CMD, s_raw_crash_data.pc);
441 append_addrs_to_hint(hint,
sizeof(hint),
pos, s_raw_crash_data.backtrace, s_raw_crash_data.backtrace_count,
442 s_raw_crash_data.reg_frame_count);
443 ESP_LOGE(TAG,
"%s", hint);
444#if SOC_CPU_CORES_NUM > 1
445 if (s_raw_crash_data.other_backtrace_count > 0) {
446 pos = snprintf(hint,
sizeof(hint),
"Other core: %s", ADDR2LINE_CMD);
447 append_addrs_to_hint(hint,
sizeof(hint),
pos, s_raw_crash_data.other_backtrace,
448 s_raw_crash_data.other_backtrace_count, s_raw_crash_data.other_reg_frame_count);
449 ESP_LOGE(TAG,
"%s", hint);
467 s_raw_crash_data.pc = (
uint32_t) info->addr;
468 s_raw_crash_data.backtrace_count = 0;
469 s_raw_crash_data.reg_frame_count = 0;
470 s_raw_crash_data.exception = (uint8_t) info->exception;
471 s_raw_crash_data.pseudo_excause = info->pseudo_excause ? 1 : 0;
472 s_raw_crash_data.crashed_core = (uint8_t) info->core;
474 s_raw_crash_data.cause = 0;
475 s_raw_crash_data.fault_addr = 0;
480 s_raw_crash_data.build_time = esphome::esp32::s_current_build_time;
481#if SOC_CPU_CORES_NUM > 1
482 s_raw_crash_data.other_backtrace_count = 0;
483 s_raw_crash_data.other_reg_frame_count = 0;
486#if CONFIG_IDF_TARGET_ARCH_XTENSA
488 if (info->frame !=
nullptr) {
489 auto *xt_frame = (XtExcFrame *) info->frame;
490 s_raw_crash_data.cause = xt_frame->exccause;
491 s_raw_crash_data.fault_addr = xt_frame->excvaddr;
492 s_raw_crash_data.backtrace_count = walk_xtensa_backtrace(xt_frame, s_raw_crash_data.backtrace, MAX_BACKTRACE);
495#if SOC_CPU_CORES_NUM > 1
499 if (info->core >= 0 && info->core < SOC_CPU_CORES_NUM) {
500 int other_core = 1 - info->core;
501 auto *other_frame = (XtExcFrame *) g_exc_frames[other_core];
502 if (other_frame !=
nullptr) {
503 s_raw_crash_data.other_backtrace_count =
504 walk_xtensa_backtrace(other_frame, s_raw_crash_data.other_backtrace, MAX_BACKTRACE);
509#elif CONFIG_IDF_TARGET_ARCH_RISCV
511 if (info->frame !=
nullptr) {
512 auto *rv_frame = (RvExcFrame *) info->frame;
513 s_raw_crash_data.cause = rv_frame->mcause;
514 s_raw_crash_data.fault_addr = rv_frame->mtval;
515 s_raw_crash_data.backtrace_count =
516 capture_riscv_backtrace(rv_frame, s_raw_crash_data.backtrace, MAX_BACKTRACE, &s_raw_crash_data.reg_frame_count);
519#if SOC_CPU_CORES_NUM > 1
521 if (info->core >= 0 && info->core < SOC_CPU_CORES_NUM) {
522 int other_core = 1 - info->core;
523 auto *other_frame = (RvExcFrame *) g_exc_frames[other_core];
524 if (other_frame !=
nullptr) {
525 s_raw_crash_data.other_backtrace_count = capture_riscv_backtrace(
526 other_frame, s_raw_crash_data.other_backtrace, MAX_BACKTRACE, &s_raw_crash_data.other_reg_frame_count);
533 s_raw_crash_data.version = CRASH_DATA_VERSION;
534 s_raw_crash_data.magic = CRASH_MAGIC;