abort handler: Fix abort stack trace when abort() called in ISR

Previously, this resulted in task stack frames turning up incorrectly in the backtrace, ie

Backtrace: 0x400d22a0:0x3ffb0fa0 0x40085a3c:0x3ffb0fc0 0x400f32c4:0x3ffb0fe0 0x40081965:0x3ffb1010
0x400d22a0: esp_vApplicationIdleHook at /home/esp/esp-idf/components/esp32/./freertos_hooks.c:
52
0x40085a3c: prvIdleTask at /home/esp/esp-idf/components/freertos/./tasks.c:4431
0x400f32c4: i2c_isr_handler_default at /home/esp/esp-idf/components/driver/./i2c.c:598
0x40081965: _xt_lowint1 at xtensa_vectors.o:?

Fix is to implement abort() via an unhandled exception rather than a breakpoint, I think
because of relative priority of exception types.

Another approach would be to assign a software-only INUM to abort()ing and defined a
PANIC_RSN_ABORTED, but this is more complex and interrupt numbers are more scarce than RAM!
This commit is contained in:
Angus Gratton
2017-06-08 15:21:03 +10:00
committed by Angus Gratton
parent 82b8b1db1f
commit 47e789f538

View File

@@ -119,7 +119,9 @@ static __attribute__((noreturn)) inline void invoke_abort()
esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, ESP_APPTRACE_TRAX_BLOCK_SIZE*CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TRAX_THRESH/100, CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO); esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, ESP_APPTRACE_TRAX_BLOCK_SIZE*CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TRAX_THRESH/100, CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO);
#endif #endif
while(1) { while(1) {
__asm__ ("break 0,0"); if (esp_cpu_in_ocd_debug_mode()) {
__asm__ ("break 0,0");
}
*((int*) 0) = 0; *((int*) 0) = 0;
} }
} }
@@ -127,7 +129,7 @@ static __attribute__((noreturn)) inline void invoke_abort()
void abort() void abort()
{ {
#if !CONFIG_ESP32_PANIC_SILENT_REBOOT #if !CONFIG_ESP32_PANIC_SILENT_REBOOT
ets_printf("abort() was called at PC 0x%08x on core %d\n", (intptr_t)__builtin_return_address(0) - 3, xPortGetCoreID()); ets_printf("abort() was called at PC 0x%08x on core %d\r\n", (intptr_t)__builtin_return_address(0) - 3, xPortGetCoreID());
#endif #endif
invoke_abort(); invoke_abort();
} }
@@ -146,6 +148,7 @@ static const char *edesc[] = {
"Cp4Dis", "Cp5Dis", "Cp6Dis", "Cp7Dis" "Cp4Dis", "Cp5Dis", "Cp6Dis", "Cp7Dis"
}; };
#define NUM_EDESCS (sizeof(edesc) / sizeof(char *))
static void commonErrorHandler(XtExcFrame *frame); static void commonErrorHandler(XtExcFrame *frame);
@@ -197,40 +200,36 @@ void panicHandler(XtExcFrame *frame)
panicPutStr("Guru Meditation Error: Core "); panicPutStr("Guru Meditation Error: Core ");
panicPutDec(core_id); panicPutDec(core_id);
panicPutStr(" panic'ed ("); panicPutStr(" panic'ed (");
if (!abort_called) { panicPutStr(reason);
panicPutStr(reason); panicPutStr(")\r\n");
panicPutStr(")\r\n"); if (frame->exccause == PANIC_RSN_DEBUGEXCEPTION) {
if (frame->exccause == PANIC_RSN_DEBUGEXCEPTION) { int debugRsn;
int debugRsn; asm("rsr.debugcause %0":"=r"(debugRsn));
asm("rsr.debugcause %0":"=r"(debugRsn)); panicPutStr("Debug exception reason: ");
panicPutStr("Debug exception reason: "); if (debugRsn&XCHAL_DEBUGCAUSE_ICOUNT_MASK) panicPutStr("SingleStep ");
if (debugRsn&XCHAL_DEBUGCAUSE_ICOUNT_MASK) panicPutStr("SingleStep "); if (debugRsn&XCHAL_DEBUGCAUSE_IBREAK_MASK) panicPutStr("HwBreakpoint ");
if (debugRsn&XCHAL_DEBUGCAUSE_IBREAK_MASK) panicPutStr("HwBreakpoint "); if (debugRsn&XCHAL_DEBUGCAUSE_DBREAK_MASK) {
if (debugRsn&XCHAL_DEBUGCAUSE_DBREAK_MASK) { //Unlike what the ISA manual says, this core seemingly distinguishes from a DBREAK
//Unlike what the ISA manual says, this core seemingly distinguishes from a DBREAK //reason caused by watchdog 0 and one caused by watchdog 1 by setting bit 8 of the
//reason caused by watchdog 0 and one caused by watchdog 1 by setting bit 8 of the //debugcause if the cause is watchdog 1 and clearing it if it's watchdog 0.
//debugcause if the cause is watchdog 1 and clearing it if it's watchdog 0. if (debugRsn&(1<<8)) {
if (debugRsn&(1<<8)) {
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK #if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
const char *name = pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(core_id)); const char *name = pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(core_id));
panicPutStr("Stack canary watchpoint triggered ("); panicPutStr("Stack canary watchpoint triggered (");
panicPutStr(name); panicPutStr(name);
panicPutStr(") "); panicPutStr(") ");
#else #else
panicPutStr("Watchpoint 1 triggered "); panicPutStr("Watchpoint 1 triggered ");
#endif #endif
} else { } else {
panicPutStr("Watchpoint 0 triggered "); panicPutStr("Watchpoint 0 triggered ");
}
}
if (debugRsn&XCHAL_DEBUGCAUSE_BREAK_MASK) panicPutStr("BREAK instr ");
if (debugRsn&XCHAL_DEBUGCAUSE_BREAKN_MASK) panicPutStr("BREAKN instr ");
if (debugRsn&XCHAL_DEBUGCAUSE_DEBUGINT_MASK) panicPutStr("DebugIntr ");
panicPutStr("\r\n");
} }
} else { }
panicPutStr("abort)\r\n"); if (debugRsn&XCHAL_DEBUGCAUSE_BREAK_MASK) panicPutStr("BREAK instr ");
} if (debugRsn&XCHAL_DEBUGCAUSE_BREAKN_MASK) panicPutStr("BREAKN instr ");
if (debugRsn&XCHAL_DEBUGCAUSE_DEBUGINT_MASK) panicPutStr("DebugIntr ");
panicPutStr("\r\n");
}
if (esp_cpu_in_ocd_debug_mode()) { if (esp_cpu_in_ocd_debug_mode()) {
#if CONFIG_ESP32_APPTRACE_ENABLE #if CONFIG_ESP32_APPTRACE_ENABLE
@@ -245,28 +244,30 @@ void panicHandler(XtExcFrame *frame)
void xt_unhandled_exception(XtExcFrame *frame) void xt_unhandled_exception(XtExcFrame *frame)
{ {
haltOtherCore(); haltOtherCore();
panicPutStr("Guru Meditation Error of type "); if (!abort_called) {
int exccause = frame->exccause; panicPutStr("Guru Meditation Error of type ");
if (exccause < 40) { int exccause = frame->exccause;
panicPutStr(edesc[exccause]); if (exccause < NUM_EDESCS) {
} else { panicPutStr(edesc[exccause]);
panicPutStr("Unknown"); } else {
} panicPutStr("Unknown");
panicPutStr(" occurred on core "); }
panicPutDec(xPortGetCoreID()); panicPutStr(" occurred on core ");
if (esp_cpu_in_ocd_debug_mode()) { panicPutDec(xPortGetCoreID());
panicPutStr(" at pc="); if (esp_cpu_in_ocd_debug_mode()) {
panicPutHex(frame->pc); panicPutStr(" at pc=");
panicPutStr(". Setting bp and returning..\r\n"); panicPutHex(frame->pc);
panicPutStr(". Setting bp and returning..\r\n");
#if CONFIG_ESP32_APPTRACE_ENABLE #if CONFIG_ESP32_APPTRACE_ENABLE
esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, ESP_APPTRACE_TRAX_BLOCK_SIZE*CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TRAX_THRESH/100, CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO); esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, ESP_APPTRACE_TRAX_BLOCK_SIZE*CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TRAX_THRESH/100, CONFIG_ESP32_APPTRACE_ONPANIC_HOST_FLUSH_TMO);
#endif #endif
//Stick a hardware breakpoint on the address the handler returns to. This way, the OCD debugger //Stick a hardware breakpoint on the address the handler returns to. This way, the OCD debugger
//will kick in exactly at the context the error happened. //will kick in exactly at the context the error happened.
setFirstBreakpoint(frame->pc); setFirstBreakpoint(frame->pc);
return; return;
}
panicPutStr(". Exception was unhandled.\r\n");
} }
panicPutStr(". Exception was unhandled.\r\n");
commonErrorHandler(frame); commonErrorHandler(frame);
} }
@@ -389,7 +390,7 @@ void esp_restart_noos() __attribute__ ((noreturn));
We arrive here after a panic or unhandled exception, when no OCD is detected. Dump the registers to the We arrive here after a panic or unhandled exception, when no OCD is detected. Dump the registers to the
serial port and either jump to the gdb stub, halt the CPU or reboot. serial port and either jump to the gdb stub, halt the CPU or reboot.
*/ */
static void commonErrorHandler(XtExcFrame *frame) static __attribute__((noreturn)) void commonErrorHandler(XtExcFrame *frame)
{ {
int *regs = (int *)frame; int *regs = (int *)frame;
int x, y; int x, y;