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);
#endif
while(1) {
__asm__ ("break 0,0");
if (esp_cpu_in_ocd_debug_mode()) {
__asm__ ("break 0,0");
}
*((int*) 0) = 0;
}
}
@ -127,7 +129,7 @@ static __attribute__((noreturn)) inline void invoke_abort()
void abort()
{
#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
invoke_abort();
}
@ -146,6 +148,7 @@ static const char *edesc[] = {
"Cp4Dis", "Cp5Dis", "Cp6Dis", "Cp7Dis"
};
#define NUM_EDESCS (sizeof(edesc) / sizeof(char *))
static void commonErrorHandler(XtExcFrame *frame);
@ -197,40 +200,36 @@ void panicHandler(XtExcFrame *frame)
panicPutStr("Guru Meditation Error: Core ");
panicPutDec(core_id);
panicPutStr(" panic'ed (");
if (!abort_called) {
panicPutStr(reason);
panicPutStr(")\r\n");
if (frame->exccause == PANIC_RSN_DEBUGEXCEPTION) {
int debugRsn;
asm("rsr.debugcause %0":"=r"(debugRsn));
panicPutStr("Debug exception reason: ");
if (debugRsn&XCHAL_DEBUGCAUSE_ICOUNT_MASK) panicPutStr("SingleStep ");
if (debugRsn&XCHAL_DEBUGCAUSE_IBREAK_MASK) panicPutStr("HwBreakpoint ");
if (debugRsn&XCHAL_DEBUGCAUSE_DBREAK_MASK) {
//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
//debugcause if the cause is watchdog 1 and clearing it if it's watchdog 0.
if (debugRsn&(1<<8)) {
panicPutStr(reason);
panicPutStr(")\r\n");
if (frame->exccause == PANIC_RSN_DEBUGEXCEPTION) {
int debugRsn;
asm("rsr.debugcause %0":"=r"(debugRsn));
panicPutStr("Debug exception reason: ");
if (debugRsn&XCHAL_DEBUGCAUSE_ICOUNT_MASK) panicPutStr("SingleStep ");
if (debugRsn&XCHAL_DEBUGCAUSE_IBREAK_MASK) panicPutStr("HwBreakpoint ");
if (debugRsn&XCHAL_DEBUGCAUSE_DBREAK_MASK) {
//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
//debugcause if the cause is watchdog 1 and clearing it if it's watchdog 0.
if (debugRsn&(1<<8)) {
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
const char *name = pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(core_id));
panicPutStr("Stack canary watchpoint triggered (");
panicPutStr(name);
panicPutStr(") ");
const char *name = pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(core_id));
panicPutStr("Stack canary watchpoint triggered (");
panicPutStr(name);
panicPutStr(") ");
#else
panicPutStr("Watchpoint 1 triggered ");
panicPutStr("Watchpoint 1 triggered ");
#endif
} else {
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("Watchpoint 0 triggered ");
}
} 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 CONFIG_ESP32_APPTRACE_ENABLE
@ -245,28 +244,30 @@ void panicHandler(XtExcFrame *frame)
void xt_unhandled_exception(XtExcFrame *frame)
{
haltOtherCore();
panicPutStr("Guru Meditation Error of type ");
int exccause = frame->exccause;
if (exccause < 40) {
panicPutStr(edesc[exccause]);
} else {
panicPutStr("Unknown");
}
panicPutStr(" occurred on core ");
panicPutDec(xPortGetCoreID());
if (esp_cpu_in_ocd_debug_mode()) {
panicPutStr(" at pc=");
panicPutHex(frame->pc);
panicPutStr(". Setting bp and returning..\r\n");
if (!abort_called) {
panicPutStr("Guru Meditation Error of type ");
int exccause = frame->exccause;
if (exccause < NUM_EDESCS) {
panicPutStr(edesc[exccause]);
} else {
panicPutStr("Unknown");
}
panicPutStr(" occurred on core ");
panicPutDec(xPortGetCoreID());
if (esp_cpu_in_ocd_debug_mode()) {
panicPutStr(" at pc=");
panicPutHex(frame->pc);
panicPutStr(". Setting bp and returning..\r\n");
#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
//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.
setFirstBreakpoint(frame->pc);
return;
//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.
setFirstBreakpoint(frame->pc);
return;
}
panicPutStr(". Exception was unhandled.\r\n");
}
panicPutStr(". Exception was unhandled.\r\n");
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
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 x, y;