]> granicus.if.org Git - esp-idf/blob - components/esp32/panic.c
ESP_ERROR_CHECK converts error code to text
[esp-idf] / components / esp32 / panic.c
1 // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2 //
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
6
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
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.
14 #include <stdlib.h>
15
16 #include <xtensa/config/core.h>
17
18 #include "rom/rtc.h"
19 #include "rom/uart.h"
20
21 #include "freertos/FreeRTOS.h"
22 #include "freertos/task.h"
23 #include "freertos/xtensa_api.h"
24
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"
31 #include "soc/cpu.h"
32 #include "soc/rtc.h"
33
34 #include "esp_gdbstub.h"
35 #include "esp_panic.h"
36 #include "esp_attr.h"
37 #include "esp_err.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"
46 #endif
47
48 #if CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO == -1
49 #define APPTRACE_ONPANIC_HOST_FLUSH_TMO   ESP_APPTRACE_TMO_INFINITE
50 #else
51 #define APPTRACE_ONPANIC_HOST_FLUSH_TMO   (1000*CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO)
52 #endif
53 /*
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.
57 */
58
59 /*
60   Note: The linker script will put everything in this file in IRAM/DRAM, so it also works with flash cache disabled.
61 */
62
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)
66 {
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);
69 }
70
71 static void panicPutStr(const char *c)
72 {
73     int x = 0;
74     while (c[x] != 0) {
75         panicPutChar(c[x]);
76         x++;
77     }
78 }
79
80 static void panicPutHex(int a)
81 {
82     int x;
83     int c;
84     for (x = 0; x < 8; x++) {
85         c = (a >> 28) & 0xf;
86         if (c < 10) {
87             panicPutChar('0' + c);
88         } else {
89             panicPutChar('a' + c - 10);
90         }
91         a <<= 4;
92     }
93 }
94
95 static void panicPutDec(int a)
96 {
97     int n1, n2;
98     n1 = a % 10;
99     n2 = a / 10;
100     if (n2 == 0) {
101         panicPutChar(' ');
102     } else {
103         panicPutChar(n2 + '0');
104     }
105     panicPutChar(n1 + '0');
106 }
107 #else
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) { }
113 #endif
114
115 void  __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
116 {
117     panicPutStr("***ERROR*** A stack overflow in task ");
118     panicPutStr((char *)pcTaskName);
119     panicPutStr(" has been detected.\r\n");
120     abort();
121 }
122
123 static bool abort_called;
124
125 static __attribute__((noreturn)) inline void invoke_abort()
126 {
127     abort_called = true;
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);
131 #else
132     esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH,
133                               APPTRACE_ONPANIC_HOST_FLUSH_TMO);
134 #endif
135 #endif
136     while (1) {
137         if (esp_cpu_in_ocd_debug_mode()) {
138             __asm__ ("break 0,0");
139         }
140         *((int *) 0) = 0;
141     }
142 }
143
144 void abort()
145 {
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());
148 #endif
149     invoke_abort();
150 }
151
152
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"
164 };
165
166 #define NUM_EDESCS (sizeof(edesc) / sizeof(char *))
167
168 static void commonErrorHandler(XtExcFrame *frame);
169 static inline void disableAllWdts();
170
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()
174 {
175     esp_cpu_stall( xPortGetCoreID() == 0 ? 1 : 0 );
176 }
177
178
179 static void setFirstBreakpoint(uint32_t pc)
180 {
181     asm(
182         "wsr.ibreaka0 %0\n" \
183         "rsr.ibreakenable a3\n" \
184         "movi a4,1\n" \
185         "or a4, a4, a3\n" \
186         "wsr.ibreakenable a4\n" \
187         ::"r"(pc):"a3", "a4");
188 }
189
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
196
197 void panicHandler(XtExcFrame *frame)
198 {
199     int core_id = xPortGetCoreID();
200     //Please keep in sync with PANIC_RSN_* defines
201     const char *reasons[] = {
202         "Unknown reason",
203         "Unhandled debug exception",
204         "Double 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",
210     };
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];
215     }
216
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;
221         while (1);
222     }
223
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) {
226         ets_delay_us(1);
227     }
228
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
231         // on the other CPU.
232         while (1);
233     }
234 #endif //!CONFIG_FREERTOS_UNICORE
235
236     haltOtherCore();
237     esp_dport_access_int_abort();
238     panicPutStr("Guru Meditation Error: Core ");
239     panicPutDec(core_id);
240     panicPutStr(" panic'ed (");
241     panicPutStr(reason);
242     panicPutStr(")\r\n");
243     if (frame->exccause == PANIC_RSN_DEBUGEXCEPTION) {
244         int debugRsn;
245         asm("rsr.debugcause %0":"=r"(debugRsn));
246         panicPutStr("Debug exception reason: ");
247         if (debugRsn & XCHAL_DEBUGCAUSE_ICOUNT_MASK) {
248             panicPutStr("SingleStep ");
249         }
250         if (debugRsn & XCHAL_DEBUGCAUSE_IBREAK_MASK) {
251             panicPutStr("HwBreakpoint ");
252         }
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 (");
261                 panicPutStr(name);
262                 panicPutStr(") ");
263 #else
264                 panicPutStr("Watchpoint 1 triggered ");
265 #endif
266             } else {
267                 panicPutStr("Watchpoint 0 triggered ");
268             }
269         }
270         if (debugRsn & XCHAL_DEBUGCAUSE_BREAK_MASK) {
271             panicPutStr("BREAK instr ");
272         }
273         if (debugRsn & XCHAL_DEBUGCAUSE_BREAKN_MASK) {
274             panicPutStr("BREAKN instr ");
275         }
276         if (debugRsn & XCHAL_DEBUGCAUSE_DEBUGINT_MASK) {
277             panicPutStr("DebugIntr ");
278         }
279         panicPutStr("\r\n");
280     }
281
282     if (esp_cpu_in_ocd_debug_mode()) {
283         disableAllWdts();
284         if (frame->exccause == PANIC_RSN_INTWDT_CPU0 ||
285             frame->exccause == PANIC_RSN_INTWDT_CPU1) {
286             TIMERG1.int_clr_timers.wdt = 1;
287         }
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);
291 #else
292         esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH,
293                                   APPTRACE_ONPANIC_HOST_FLUSH_TMO);
294 #endif
295 #endif
296         setFirstBreakpoint(frame->pc);
297         return;
298     }
299     commonErrorHandler(frame);
300 }
301
302 void xt_unhandled_exception(XtExcFrame *frame)
303 {
304     haltOtherCore();
305     esp_dport_access_int_abort();
306     if (!abort_called) {
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]);
313         } else {
314             panicPutStr("Unknown");
315         }
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);
324 #else
325             esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH,
326                                       APPTRACE_ONPANIC_HOST_FLUSH_TMO);
327 #endif
328 #endif
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);
332             return;
333         }
334         panicPutStr(". Exception was unhandled.\r\n");
335     }
336     commonErrorHandler(frame);
337 }
338
339
340 /*
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
345   one second.
346 */
347 static void reconfigureAllWdts()
348 {
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;
358     //Disable wdt 1
359     TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
360     TIMERG1.wdt_config0.en = 0;
361     TIMERG1.wdt_wprotect = 0;
362 }
363
364 /*
365   This disables all the watchdogs for when we call the gdbstub.
366 */
367 static inline void disableAllWdts()
368 {
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;
375 }
376
377 static void esp_panic_wdt_start()
378 {
379     if (REG_GET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN)) {
380         return;
381     }
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);
392 }
393
394 void esp_panic_wdt_stop()
395 {
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);
401 }
402
403 static void esp_panic_dig_reset() __attribute__((noreturn));
404
405 static void esp_panic_dig_reset()
406 {
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);
414     while (true) {
415         ;
416     }
417 }
418
419 static void putEntry(uint32_t pc, uint32_t sp)
420 {
421     if (pc & 0x80000000) {
422         pc = (pc & 0x3fffffff) | 0x40000000;
423     }
424     panicPutStr(" 0x");
425     panicPutHex(pc);
426     panicPutStr(":0x");
427     panicPutHex(sp);
428 }
429
430 static void doBacktrace(XtExcFrame *frame)
431 {
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. */
435     putEntry(pc, sp);
436     pc = frame->a0;
437     while (i++ < 100) {
438         uint32_t psp = sp;
439         if (!esp_stack_ptr_is_sane(sp) || i++ > 100) {
440             break;
441         }
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) {
446             break;
447         }
448     }
449     panicPutStr("\r\n\r\n");
450 }
451
452 /*
453  * Dump registers and do backtrace.
454  */
455 static void commonErrorHandler_dump(XtExcFrame *frame, int core_id)
456 {
457     int *regs = (int *)frame;
458     int x, y;
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  "
463     };
464
465     /* only dump registers for 'real' crashes, if crashing via abort()
466        the register window is no longer useful.
467     */
468     if (!abort_called) {
469         panicPutStr("Core");
470         panicPutDec(core_id);
471         panicPutStr(" register dump:\r\n");
472
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]);
477                     panicPutStr(": 0x");
478                     panicPutHex(regs[x + y + 1]);
479                     panicPutStr("  ");
480                 }
481             }
482             panicPutStr("\r\n");
483         }
484
485         if (xPortInterruptedFromISRContext()
486 #if !CONFIG_FREERTOS_UNICORE
487             && other_core_frame != frame
488 #endif //!CONFIG_FREERTOS_UNICORE
489             ) {
490             //If the core which triggers the interrupt watchdog was in ISR context, dump the epc registers.
491             uint32_t __value;
492             panicPutStr("Core");
493             panicPutDec(core_id);
494             panicPutStr(" was running in ISR context:\r\n");
495
496             __asm__("rsr.epc1 %0" : "=a"(__value));
497             panicPutStr("EPC1    : 0x");
498             panicPutHex(__value);
499
500             __asm__("rsr.epc2 %0" : "=a"(__value));
501             panicPutStr("  EPC2    : 0x");
502             panicPutHex(__value);
503
504             __asm__("rsr.epc3 %0" : "=a"(__value));
505             panicPutStr("  EPC3    : 0x");
506             panicPutHex(__value);
507
508             __asm__("rsr.epc4 %0" : "=a"(__value));
509             panicPutStr("  EPC4    : 0x");
510             panicPutHex(__value);
511
512             panicPutStr("\r\n");
513         }
514
515     }
516
517     /* With windowed ABI backtracing is easy, let's do it. */
518     doBacktrace(frame);
519
520 }
521
522 /*
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.
525 */
526 static __attribute__((noreturn)) void commonErrorHandler(XtExcFrame *frame)
527 {
528
529     int core_id = xPortGetCoreID();
530     // start panic WDT to restart system if we hang in this handler
531     esp_panic_wdt_start();
532
533     //Feed the watchdogs, so they will give us time to print out debug info
534     reconfigureAllWdts();
535
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));
540     }
541 #endif //!CONFIG_FREERTOS_UNICORE
542
543 #if CONFIG_ESP32_APPTRACE_ENABLE
544     disableAllWdts();
545 #if CONFIG_SYSVIEW_ENABLE
546     SEGGER_RTT_ESP32_FlushNoLock(CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO);
547 #else
548     esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_ESP32_APPTRACE_POSTMORTEM_FLUSH_TRAX_THRESH,
549                               APPTRACE_ONPANIC_HOST_FLUSH_TMO);
550 #endif
551     reconfigureAllWdts();
552 #endif
553
554 #if CONFIG_ESP32_PANIC_GDBSTUB
555     disableAllWdts();
556     esp_panic_wdt_stop();
557     panicPutStr("Entering gdb stub now.\r\n");
558     esp_gdbstub_panic_handler(frame);
559 #else
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");
564     } else {
565         disableAllWdts();
566         s_dumping_core = true;
567 #if CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH
568         esp_core_dump_to_flash(frame);
569 #endif
570 #if CONFIG_ESP32_ENABLE_COREDUMP_TO_UART && !CONFIG_ESP32_PANIC_SILENT_REBOOT
571         esp_core_dump_to_uart(frame);
572 #endif
573         s_dumping_core = false;
574         reconfigureAllWdts();
575     }
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) {
581         esp_restart_noos();
582     } else {
583         // The only way to clear invalid cache access interrupt is to reset the digital part
584         esp_panic_dig_reset();
585     }
586 #else
587     disableAllWdts();
588     panicPutStr("CPU halted.\r\n");
589     while (1);
590 #endif /* CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT */
591 #endif /* CONFIG_ESP32_PANIC_GDBSTUB */
592 }
593
594
595 void esp_set_breakpoint_if_jtag(void *fn)
596 {
597     if (esp_cpu_in_ocd_debug_mode()) {
598         setFirstBreakpoint((uint32_t)fn);
599     }
600 }
601
602
603 esp_err_t esp_set_watchpoint(int no, void *adr, int size, int flags)
604 {
605     int x;
606     if (no < 0 || no > 1) {
607         return ESP_ERR_INVALID_ARG;
608     }
609     if (flags & (~0xC0000000)) {
610         return ESP_ERR_INVALID_ARG;
611     }
612     int dbreakc = 0x3F;
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)) {
616             break;
617         }
618         dbreakc <<= 1;
619     }
620     if (x == 7) {
621         return ESP_ERR_INVALID_ARG;
622     }
623     //Mask mask and add in flags.
624     dbreakc = (dbreakc & 0x3f) | flags;
625
626     if (no == 0) {
627         asm volatile(
628             "wsr.dbreaka0 %0\n" \
629             "wsr.dbreakc0 %1\n" \
630             ::"r"(adr), "r"(dbreakc));
631     } else {
632         asm volatile(
633             "wsr.dbreaka1 %0\n" \
634             "wsr.dbreakc1 %1\n" \
635             ::"r"(adr), "r"(dbreakc));
636     }
637     return ESP_OK;
638 }
639
640 void esp_clear_watchpoint(int no)
641 {
642     //Setting a dbreakc register to 0 makes it trigger on neither load nor store, effectively disabling it.
643     int dbreakc = 0;
644     if (no == 0) {
645         asm volatile(
646             "wsr.dbreakc0 %0\n" \
647             ::"r"(dbreakc));
648     } else {
649         asm volatile(
650             "wsr.dbreakc1 %0\n" \
651             ::"r"(dbreakc));
652     }
653 }
654
655 void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression)
656 {
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);
664     }
665     invoke_abort();
666 }