1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
16 #include <xtensa/config/core.h>
21 #include "freertos/FreeRTOS.h"
22 #include "freertos/task.h"
23 #include "freertos/xtensa_api.h"
25 #include "soc/uart_reg.h"
26 #include "soc/io_mux_reg.h"
27 #include "soc/dport_reg.h"
28 #include "soc/rtc_cntl_reg.h"
29 #include "soc/timer_group_struct.h"
30 #include "soc/timer_group_reg.h"
34 #include "esp_gdbstub.h"
35 #include "esp_panic.h"
38 #include "esp_core_dump.h"
39 #include "esp_spi_flash.h"
40 #include "esp_cache_err_int.h"
41 #include "esp_app_trace.h"
42 #include "esp_system.h"
43 #include "sdkconfig.h"
44 #if CONFIG_SYSVIEW_ENABLE
45 #include "SEGGER_RTT.h"
48 #if CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO == -1
49 #define APPTRACE_ONPANIC_HOST_FLUSH_TMO ESP_APPTRACE_TMO_INFINITE
51 #define APPTRACE_ONPANIC_HOST_FLUSH_TMO (1000*CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO)
54 Panic handlers; these get called when an unhandled exception occurs or the assembly-level
55 task switching / interrupt code runs into an unrecoverable error. The default task stack
56 overflow handler and abort handler are also in here.
60 Note: The linker script will put everything in this file in IRAM/DRAM, so it also works with flash cache disabled.
63 #if !CONFIG_ESP32_PANIC_SILENT_REBOOT
64 //printf may be broken, so we fix our own printing fns...
65 static void panicPutChar(char c)
67 while (((READ_PERI_REG(UART_STATUS_REG(CONFIG_CONSOLE_UART_NUM)) >> UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT) >= 126) ;
68 WRITE_PERI_REG(UART_FIFO_REG(CONFIG_CONSOLE_UART_NUM), c);
71 static void panicPutStr(const char *c)
80 static void panicPutHex(int a)
84 for (x = 0; x < 8; x++) {
87 panicPutChar('0' + c);
89 panicPutChar('a' + c - 10);
95 static void panicPutDec(int a)
103 panicPutChar(n2 + '0');
105 panicPutChar(n1 + '0');
108 //No printing wanted. Stub out these functions.
109 static void panicPutChar(char c) { }
110 static void panicPutStr(const char *c) { }
111 static void panicPutHex(int a) { }
112 static void panicPutDec(int a) { }
115 void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
117 panicPutStr("***ERROR*** A stack overflow in task ");
118 panicPutStr((char *)pcTaskName);
119 panicPutStr(" has been detected.\r\n");
123 static bool abort_called;
125 static __attribute__((noreturn)) inline void invoke_abort()
128 #if CONFIG_ESP32_APPTRACE_ENABLE
129 #if CONFIG_SYSVIEW_ENABLE
130 SEGGER_RTT_ESP32_FlushNoLock(CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO);
132 esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH,
133 APPTRACE_ONPANIC_HOST_FLUSH_TMO);
137 if (esp_cpu_in_ocd_debug_mode()) {
138 __asm__ ("break 0,0");
146 #if !CONFIG_ESP32_PANIC_SILENT_REBOOT
147 ets_printf("abort() was called at PC 0x%08x on core %d\r\n", (intptr_t)__builtin_return_address(0) - 3, xPortGetCoreID());
153 static const char *edesc[] = {
154 "IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError",
155 "Level1Interrupt", "Alloca", "IntegerDivideByZero", "PCValue",
156 "Privileged", "LoadStoreAlignment", "res", "res",
157 "InstrPDAddrError", "LoadStorePIFDataError", "InstrPIFAddrError", "LoadStorePIFAddrError",
158 "InstTLBMiss", "InstTLBMultiHit", "InstFetchPrivilege", "res",
159 "InstrFetchProhibited", "res", "res", "res",
160 "LoadStoreTLBMiss", "LoadStoreTLBMultihit", "LoadStorePrivilege", "res",
161 "LoadProhibited", "StoreProhibited", "res", "res",
162 "Cp0Dis", "Cp1Dis", "Cp2Dis", "Cp3Dis",
163 "Cp4Dis", "Cp5Dis", "Cp6Dis", "Cp7Dis"
166 #define NUM_EDESCS (sizeof(edesc) / sizeof(char *))
168 static void commonErrorHandler(XtExcFrame *frame);
169 static inline void disableAllWdts();
171 //The fact that we've panic'ed probably means the other CPU is now running wild, possibly
172 //messing up the serial output, so we stall it here.
173 static void haltOtherCore()
175 esp_cpu_stall( xPortGetCoreID() == 0 ? 1 : 0 );
179 static void setFirstBreakpoint(uint32_t pc)
182 "wsr.ibreaka0 %0\n" \
183 "rsr.ibreakenable a3\n" \
186 "wsr.ibreakenable a4\n" \
187 ::"r"(pc):"a3", "a4");
190 //When interrupt watchdog happen in one core, both cores will be interrupted.
191 //The core which doesn't trigger the interrupt watchdog will save the frame and return.
192 //The core which triggers the interrupt watchdog will use the saved frame, and dump frames for both cores.
193 #if !CONFIG_FREERTOS_UNICORE
194 static volatile XtExcFrame * other_core_frame = NULL;
195 #endif //!CONFIG_FREERTOS_UNICORE
197 void panicHandler(XtExcFrame *frame)
199 int core_id = xPortGetCoreID();
200 //Please keep in sync with PANIC_RSN_* defines
201 const char *reasons[] = {
203 "Unhandled debug exception",
205 "Unhandled kernel exception",
206 "Coprocessor exception",
207 "Interrupt wdt timeout on CPU0",
208 "Interrupt wdt timeout on CPU1",
209 "Cache disabled but cached memory region accessed",
211 const char *reason = reasons[0];
212 //The panic reason is stored in the EXCCAUSE register.
213 if (frame->exccause <= PANIC_RSN_MAX) {
214 reason = reasons[frame->exccause];
217 #if !CONFIG_FREERTOS_UNICORE
218 //Save frame for other core.
219 if ((frame->exccause == PANIC_RSN_INTWDT_CPU0 && core_id == 1) || (frame->exccause == PANIC_RSN_INTWDT_CPU1 && core_id == 0)) {
220 other_core_frame = frame;
224 //The core which triggers the interrupt watchdog will delay 1 us, so the other core can save its frame.
225 if (frame->exccause == PANIC_RSN_INTWDT_CPU0 || frame->exccause == PANIC_RSN_INTWDT_CPU1) {
229 if (frame->exccause == PANIC_RSN_CACHEERR && esp_cache_err_get_cpuid() != core_id) {
230 // Cache error interrupt will be handled by the panic handler
234 #endif //!CONFIG_FREERTOS_UNICORE
237 esp_dport_access_int_abort();
238 panicPutStr("Guru Meditation Error: Core ");
239 panicPutDec(core_id);
240 panicPutStr(" panic'ed (");
242 panicPutStr(")\r\n");
243 if (frame->exccause == PANIC_RSN_DEBUGEXCEPTION) {
245 asm("rsr.debugcause %0":"=r"(debugRsn));
246 panicPutStr("Debug exception reason: ");
247 if (debugRsn & XCHAL_DEBUGCAUSE_ICOUNT_MASK) {
248 panicPutStr("SingleStep ");
250 if (debugRsn & XCHAL_DEBUGCAUSE_IBREAK_MASK) {
251 panicPutStr("HwBreakpoint ");
253 if (debugRsn & XCHAL_DEBUGCAUSE_DBREAK_MASK) {
254 //Unlike what the ISA manual says, this core seemingly distinguishes from a DBREAK
255 //reason caused by watchdog 0 and one caused by watchdog 1 by setting bit 8 of the
256 //debugcause if the cause is watchdog 1 and clearing it if it's watchdog 0.
257 if (debugRsn & (1 << 8)) {
258 #if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
259 const char *name = pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(core_id));
260 panicPutStr("Stack canary watchpoint triggered (");
264 panicPutStr("Watchpoint 1 triggered ");
267 panicPutStr("Watchpoint 0 triggered ");
270 if (debugRsn & XCHAL_DEBUGCAUSE_BREAK_MASK) {
271 panicPutStr("BREAK instr ");
273 if (debugRsn & XCHAL_DEBUGCAUSE_BREAKN_MASK) {
274 panicPutStr("BREAKN instr ");
276 if (debugRsn & XCHAL_DEBUGCAUSE_DEBUGINT_MASK) {
277 panicPutStr("DebugIntr ");
282 if (esp_cpu_in_ocd_debug_mode()) {
284 if (frame->exccause == PANIC_RSN_INTWDT_CPU0 ||
285 frame->exccause == PANIC_RSN_INTWDT_CPU1) {
286 TIMERG1.int_clr_timers.wdt = 1;
288 #if CONFIG_ESP32_APPTRACE_ENABLE
289 #if CONFIG_SYSVIEW_ENABLE
290 SEGGER_RTT_ESP32_FlushNoLock(CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO);
292 esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH,
293 APPTRACE_ONPANIC_HOST_FLUSH_TMO);
296 setFirstBreakpoint(frame->pc);
299 commonErrorHandler(frame);
302 void xt_unhandled_exception(XtExcFrame *frame)
305 esp_dport_access_int_abort();
307 panicPutStr("Guru Meditation Error: Core ");
308 panicPutDec(xPortGetCoreID());
309 panicPutStr(" panic'ed (");
310 int exccause = frame->exccause;
311 if (exccause < NUM_EDESCS) {
312 panicPutStr(edesc[exccause]);
314 panicPutStr("Unknown");
316 panicPutStr(")\r\n");
317 if (esp_cpu_in_ocd_debug_mode()) {
318 panicPutStr(" at pc=");
319 panicPutHex(frame->pc);
320 panicPutStr(". Setting bp and returning..\r\n");
321 #if CONFIG_ESP32_APPTRACE_ENABLE
322 #if CONFIG_SYSVIEW_ENABLE
323 SEGGER_RTT_ESP32_FlushNoLock(CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO);
325 esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH,
326 APPTRACE_ONPANIC_HOST_FLUSH_TMO);
329 //Stick a hardware breakpoint on the address the handler returns to. This way, the OCD debugger
330 //will kick in exactly at the context the error happened.
331 setFirstBreakpoint(frame->pc);
334 panicPutStr(". Exception was unhandled.\r\n");
336 commonErrorHandler(frame);
341 If watchdogs are enabled, the panic handler runs the risk of getting aborted pre-emptively because
342 an overzealous watchdog decides to reset it. On the other hand, if we disable all watchdogs, we run
343 the risk of somehow halting in the panic handler and not resetting. That is why this routine kills
344 all watchdogs except the timer group 0 watchdog, and it reconfigures that to reset the chip after
347 static void reconfigureAllWdts()
349 TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
350 TIMERG0.wdt_feed = 1;
351 TIMERG0.wdt_config0.sys_reset_length = 7; //3.2uS
352 TIMERG0.wdt_config0.cpu_reset_length = 7; //3.2uS
353 TIMERG0.wdt_config0.stg0 = TIMG_WDT_STG_SEL_RESET_SYSTEM; //1st stage timeout: reset system
354 TIMERG0.wdt_config1.clk_prescale = 80 * 500; //Prescaler: wdt counts in ticks of 0.5mS
355 TIMERG0.wdt_config2 = 2000; //1 second before reset
356 TIMERG0.wdt_config0.en = 1;
357 TIMERG0.wdt_wprotect = 0;
359 TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
360 TIMERG1.wdt_config0.en = 0;
361 TIMERG1.wdt_wprotect = 0;
365 This disables all the watchdogs for when we call the gdbstub.
367 static inline void disableAllWdts()
369 TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
370 TIMERG0.wdt_config0.en = 0;
371 TIMERG0.wdt_wprotect = 0;
372 TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
373 TIMERG1.wdt_config0.en = 0;
374 TIMERG1.wdt_wprotect = 0;
377 static void esp_panic_wdt_start()
379 if (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN)) {
382 WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
383 WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
384 REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_SYS_RESET_LENGTH, 7);
385 REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_CPU_RESET_LENGTH, 7);
386 REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_RESET_SYSTEM);
387 // 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data.
388 // @ 115200 UART speed it will take more than 6 sec to print them out.
389 WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, rtc_clk_slow_freq_get_hz() * 7);
390 REG_SET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
391 WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
394 void esp_panic_wdt_stop()
396 WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE);
397 WRITE_PERI_REG(RTC_CNTL_WDTFEED_REG, 1);
398 REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_OFF);
399 REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
400 WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
403 static void esp_panic_dig_reset() __attribute__((noreturn));
405 static void esp_panic_dig_reset()
407 // make sure all the panic handler output is sent from UART FIFO
408 uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM);
409 // switch to XTAL (otherwise we will keep running from the PLL)
410 rtc_clk_cpu_freq_set(RTC_CPU_FREQ_XTAL);
411 // reset the digital part
412 esp_cpu_unstall(PRO_CPU_NUM);
413 SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST);
419 static void putEntry(uint32_t pc, uint32_t sp)
421 if (pc & 0x80000000) {
422 pc = (pc & 0x3fffffff) | 0x40000000;
430 static void doBacktrace(XtExcFrame *frame)
432 uint32_t i = 0, pc = frame->pc, sp = frame->a1;
433 panicPutStr("\r\nBacktrace:");
434 /* Do not check sanity on first entry, PC could be smashed. */
439 if (!esp_stack_ptr_is_sane(sp) || i++ > 100) {
442 sp = *((uint32_t *) (sp - 0x10 + 4));
443 putEntry(pc - 3, sp); // stack frame addresses are return addresses, so subtract 3 to get the CALL address
444 pc = *((uint32_t *) (psp - 0x10));
445 if (pc < 0x40000000) {
449 panicPutStr("\r\n\r\n");
453 * Dump registers and do backtrace.
455 static void commonErrorHandler_dump(XtExcFrame *frame, int core_id)
457 int *regs = (int *)frame;
459 const char *sdesc[] = {
460 "PC ", "PS ", "A0 ", "A1 ", "A2 ", "A3 ", "A4 ", "A5 ",
461 "A6 ", "A7 ", "A8 ", "A9 ", "A10 ", "A11 ", "A12 ", "A13 ",
462 "A14 ", "A15 ", "SAR ", "EXCCAUSE", "EXCVADDR", "LBEG ", "LEND ", "LCOUNT "
465 /* only dump registers for 'real' crashes, if crashing via abort()
466 the register window is no longer useful.
470 panicPutDec(core_id);
471 panicPutStr(" register dump:\r\n");
473 for (x = 0; x < 24; x += 4) {
474 for (y = 0; y < 4; y++) {
475 if (sdesc[x + y][0] != 0) {
476 panicPutStr(sdesc[x + y]);
478 panicPutHex(regs[x + y + 1]);
485 if (xPortInterruptedFromISRContext()
486 #if !CONFIG_FREERTOS_UNICORE
487 && other_core_frame != frame
488 #endif //!CONFIG_FREERTOS_UNICORE
490 //If the core which triggers the interrupt watchdog was in ISR context, dump the epc registers.
493 panicPutDec(core_id);
494 panicPutStr(" was running in ISR context:\r\n");
496 __asm__("rsr.epc1 %0" : "=a"(__value));
497 panicPutStr("EPC1 : 0x");
498 panicPutHex(__value);
500 __asm__("rsr.epc2 %0" : "=a"(__value));
501 panicPutStr(" EPC2 : 0x");
502 panicPutHex(__value);
504 __asm__("rsr.epc3 %0" : "=a"(__value));
505 panicPutStr(" EPC3 : 0x");
506 panicPutHex(__value);
508 __asm__("rsr.epc4 %0" : "=a"(__value));
509 panicPutStr(" EPC4 : 0x");
510 panicPutHex(__value);
517 /* With windowed ABI backtracing is easy, let's do it. */
523 We arrive here after a panic or unhandled exception, when no OCD is detected. Dump the registers to the
524 serial port and either jump to the gdb stub, halt the CPU or reboot.
526 static __attribute__((noreturn)) void commonErrorHandler(XtExcFrame *frame)
529 int core_id = xPortGetCoreID();
530 // start panic WDT to restart system if we hang in this handler
531 esp_panic_wdt_start();
533 //Feed the watchdogs, so they will give us time to print out debug info
534 reconfigureAllWdts();
536 commonErrorHandler_dump(frame, core_id);
537 #if !CONFIG_FREERTOS_UNICORE
538 if (other_core_frame != NULL) {
539 commonErrorHandler_dump((XtExcFrame *)other_core_frame, (core_id ? 0 : 1));
541 #endif //!CONFIG_FREERTOS_UNICORE
543 #if CONFIG_ESP32_APPTRACE_ENABLE
545 #if CONFIG_SYSVIEW_ENABLE
546 SEGGER_RTT_ESP32_FlushNoLock(CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO);
548 esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH,
549 APPTRACE_ONPANIC_HOST_FLUSH_TMO);
551 reconfigureAllWdts();
554 #if CONFIG_ESP32_PANIC_GDBSTUB
556 esp_panic_wdt_stop();
557 panicPutStr("Entering gdb stub now.\r\n");
558 esp_gdbstub_panic_handler(frame);
560 #if CONFIG_ESP32_ENABLE_COREDUMP
561 static bool s_dumping_core;
562 if (s_dumping_core) {
563 panicPutStr("Re-entered core dump! Exception happened during core dump!\r\n");
566 s_dumping_core = true;
567 #if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH
568 esp_core_dump_to_flash(frame);
570 #if CONFIG_ESP32_ENABLE_COREDUMP_TO_UART && !CONFIG_ESP32_PANIC_SILENT_REBOOT
571 esp_core_dump_to_uart(frame);
573 s_dumping_core = false;
574 reconfigureAllWdts();
576 #endif /* CONFIG_ESP32_ENABLE_COREDUMP */
577 esp_panic_wdt_stop();
578 #if CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
579 panicPutStr("Rebooting...\r\n");
580 if (frame->exccause != PANIC_RSN_CACHEERR) {
583 // The only way to clear invalid cache access interrupt is to reset the digital part
584 esp_panic_dig_reset();
588 panicPutStr("CPU halted.\r\n");
590 #endif /* CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT */
591 #endif /* CONFIG_ESP32_PANIC_GDBSTUB */
595 void esp_set_breakpoint_if_jtag(void *fn)
597 if (esp_cpu_in_ocd_debug_mode()) {
598 setFirstBreakpoint((uint32_t)fn);
603 esp_err_t esp_set_watchpoint(int no, void *adr, int size, int flags)
606 if (no < 0 || no > 1) {
607 return ESP_ERR_INVALID_ARG;
609 if (flags & (~0xC0000000)) {
610 return ESP_ERR_INVALID_ARG;
613 //We support watching 2^n byte values, from 1 to 64. Calculate the mask for that.
614 for (x = 0; x < 7; x++) {
615 if (size == (1 << x)) {
621 return ESP_ERR_INVALID_ARG;
623 //Mask mask and add in flags.
624 dbreakc = (dbreakc & 0x3f) | flags;
628 "wsr.dbreaka0 %0\n" \
629 "wsr.dbreakc0 %1\n" \
630 ::"r"(adr), "r"(dbreakc));
633 "wsr.dbreaka1 %0\n" \
634 "wsr.dbreakc1 %1\n" \
635 ::"r"(adr), "r"(dbreakc));
640 void esp_clear_watchpoint(int no)
642 //Setting a dbreakc register to 0 makes it trigger on neither load nor store, effectively disabling it.
646 "wsr.dbreakc0 %0\n" \
650 "wsr.dbreakc1 %0\n" \
655 void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression)
657 ets_printf("ESP_ERROR_CHECK failed: esp_err_t 0x%x", rc);
658 #ifdef CONFIG_ESP_ERR_TO_NAME_LOOKUP
659 ets_printf(" (%s)", esp_err_to_name(rc));
660 #endif //CONFIG_ESP_ERR_TO_NAME_LOOKUP
661 ets_printf(" at 0x%08x\n", (intptr_t)__builtin_return_address(0) - 3);
662 if (spi_flash_cache_enabled()) { // strings may be in flash cache
663 ets_printf("file: \"%s\" line %d\nfunc: %s\nexpression: %s\n", file, line, function, expression);