diff --git a/cores/esp8266/core_esp8266_postmortem.cpp b/cores/esp8266/core_esp8266_postmortem.cpp index 95844534e8..ff680f9ae0 100644 --- a/cores/esp8266/core_esp8266_postmortem.cpp +++ b/cores/esp8266/core_esp8266_postmortem.cpp @@ -75,18 +75,33 @@ extern int umm_last_fail_alloc_line; static void raise_exception() __attribute__((noreturn)); -extern void __custom_crash_callback( struct rst_info * rst_info, uint32_t stack, uint32_t stack_end ) { +extern void __custom_crash_callback(struct rst_info * rst_info, uint32_t stack, uint32_t stack_end) { (void) rst_info; (void) stack; (void) stack_end; } -extern void custom_crash_callback( struct rst_info * rst_info, uint32_t stack, uint32_t stack_end ) __attribute__ ((weak, alias("__custom_crash_callback"))); +extern void __custom_panic_callback(const char* panic_file, int panic_line, const char* panic_func, const char* panic_what) { + (void) panic_file; + (void) panic_line; + (void) panic_func; + (void) panic_what; +} + +extern void __ets_uart_putc1(char c) { + ets_uart_putc1(c); +} +extern void custom_crash_callback(struct rst_info * rst_info, uint32_t stack, uint32_t stack_end) __attribute__ ((weak, alias("__custom_crash_callback"))); + +extern void custom_panic_callback(const char* panic_file, int panic_line, const char* panic_func, const char* panic_what) __attribute__ ((weak, alias("__custom_panic_callback"))); + +extern void crash_ets_uart_putc1(char c) __attribute__((weak, alias("__ets_uart_putc1"))); // Prints need to use our library function to allow for file and function // to be safely accessed from flash. This function encapsulates snprintf() -// [which by definition will 0-terminate] and dumping to the UART +// [which by definition will 0-terminate] and dumping to the UART, or the +// user-specified function. static void ets_printf_P(const char *str, ...) { char destStr[160]; char *c = destStr; @@ -95,22 +110,28 @@ static void ets_printf_P(const char *str, ...) { vsnprintf(destStr, sizeof(destStr), str, argPtr); va_end(argPtr); while (*c) { - ets_uart_putc1(*(c++)); + crash_ets_uart_putc1(*(c++)); } } +static inline void ets_println() { ets_printf_P(PSTR("\n")); } + static void cut_here() { +#ifdef NO_CUT_HERE + return; +#endif + // https://tinyurl.com/8266dcdr => https://arduino-esp8266.readthedocs.io/en/latest/faq/a02-my-esp-crashes.html#exception ets_printf_P(PSTR("\nTo make this dump useful, DECODE IT - https://tinyurl.com/8266dcdr\n")); for (auto i = 0; i < 15; i++ ) { - ets_putc('-'); + crash_ets_uart_putc1('-'); } ets_printf_P(PSTR(" CUT HERE FOR EXCEPTION DECODER ")); for (auto i = 0; i < 15; i++ ) { - ets_putc('-'); + crash_ets_uart_putc1('-'); } - ets_putc('\n'); + ets_println(); } static inline bool is_pc_valid(uint32_t pc) { @@ -152,6 +173,7 @@ static void postmortem_report(uint32_t sp_dump) { else rst_info.reason = s_user_reset_reason; + // redirect the output to both UARTs ets_install_putc1(&uart_write_char_d); cut_here(); @@ -161,7 +183,7 @@ static void postmortem_report(uint32_t sp_dump) { if (s_panic_what) { ets_printf_P(PSTR(": Assertion '%S' failed."), s_panic_what); } - ets_putc('\n'); + ets_println(); } else if (s_panic_file) { ets_printf_P(PSTR("\nPanic %S\n"), s_panic_file); @@ -176,16 +198,15 @@ static void postmortem_report(uint32_t sp_dump) { // The GCC divide routine in ROM jumps to the address below and executes ILL (00 00 00) on div-by-zero // In that case, print the exception as (6) which is IntegerDivZero uint32_t epc1 = rst_info.epc1; - uint32_t exccause = rst_info.exccause; - bool div_zero = (exccause == 0) && (epc1 == 0x4000dce5u); + const bool div_zero = (rst_info.exccause == 0) && (epc1 == 0x4000dce5u); if (div_zero) { - exccause = 6; + rst_info.exccause = 6; // In place of the detached 'ILL' instruction., redirect attention // back to the code that called the ROM divide function. __asm__ __volatile__("rsr.excsave1 %0\n\t" : "=r"(epc1) :: "memory"); } ets_printf_P(PSTR("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n"), - exccause, epc1, rst_info.epc2, rst_info.epc3, rst_info.excvaddr, rst_info.depc); + rst_info.exccause, epc1, rst_info.epc2, rst_info.epc3, rst_info.excvaddr, rst_info.depc); } else if (rst_info.reason == REASON_SOFT_WDT_RST) { ets_printf_P(PSTR("\nSoft WDT reset")); @@ -194,7 +215,7 @@ static void postmortem_report(uint32_t sp_dump) { // The SDK is riddled with these. They are usually preceded by an ets_printf. ets_printf_P(PSTR(" - deliberate infinite loop detected")); } - ets_putc('\n'); + ets_println(); ets_printf_P(PSTR("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n"), rst_info.exccause, /* Address executing at time of Soft WDT level-1 interrupt */ rst_info.epc1, 0, 0, 0, 0); } @@ -229,7 +250,7 @@ static void postmortem_report(uint32_t sp_dump) { // 16 ?unnamed? - index into a table, pull out pointer, and call if non-zero // appears near near wDev_ProcessFiq // 32 pp_soft_wdt_feed_local - gather the specifics and call __wrap_system_restart_local - offset = 32 + 16 + 48 + 256; + offset = 32 + 16 + 48 + 256; } else if (rst_info.reason == REASON_EXCEPTION_RST) { // Stack Tally @@ -298,7 +319,11 @@ static void postmortem_report(uint32_t sp_dump) { ets_printf_P(PSTR("\nlast failed alloc caller: 0x%08x\n"), (uint32_t)umm_last_fail_alloc_addr); } - custom_crash_callback( &rst_info, sp_dump + offset, stack_end ); + if (s_panic_line || s_panic_func || s_panic_file || s_panic_what) { + custom_panic_callback(s_panic_file, s_panic_line, s_panic_func, s_panic_what); + } + + custom_crash_callback(&rst_info, sp_dump + offset, stack_end); ets_delay_us(10000); __real_system_restart_local(); @@ -309,6 +334,7 @@ static void print_stack(uint32_t start, uint32_t end) { for (uint32_t pos = start; pos < end; pos += 0x10) { uint32_t* values = (uint32_t*)(pos); +#ifdef CONT_STACKGUARD // avoid printing irrelevant data if ((values[0] == CONT_STACKGUARD) && (values[0] == values[1]) @@ -317,6 +343,7 @@ static void print_stack(uint32_t start, uint32_t end) { { continue; } +#endif // rough indicator: stack frames usually have SP saved as the second word const bool looksLikeStackFrame = (values[2] == pos + 0x10);