panic handlers: Print the PC address where abort() was called, don't dump registers

This commit is contained in:
Angus Gratton 2016-12-06 16:33:24 -08:00
parent a760eb3980
commit da977149f6
4 changed files with 63 additions and 42 deletions

View File

@ -42,3 +42,15 @@ void IRAM_ATTR esp_cpu_unstall(int cpu_id)
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_PROCPU_C0_M); CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_PROCPU_C0_M);
} }
} }
bool IRAM_ATTR esp_cpu_in_ocd_debug_mode()
{
#if CONFIG_ESP32_DEBUG_OCDAWARE
int dcr;
int reg=0x10200C; //DSRSET register
asm("rer %0,%1":"=r"(dcr):"r"(reg));
return (dcr&0x1);
#else
return false; // Always return false if "OCD aware" is disabled
#endif
}

View File

@ -94,4 +94,13 @@ void esp_cpu_stall(int cpu_id);
*/ */
void esp_cpu_unstall(int cpu_id); void esp_cpu_unstall(int cpu_id);
/**
* @brief Returns true if a JTAG debugger is attached to CPU
* OCD (on chip debug) port.
*
* @note If "Make exception and panic handlers JTAG/OCD aware"
* is disabled, this function always returns false.
*/
bool esp_cpu_in_ocd_debug_mode();
#endif #endif

View File

@ -36,7 +36,7 @@
/* /*
Panic handlers; these get called when an unhandled exception occurs or the assembly-level Panic handlers; these get called when an unhandled exception occurs or the assembly-level
task switching / interrupt code runs into an unrecoverable error. The default task stack task switching / interrupt code runs into an unrecoverable error. The default task stack
overflow handler also is in here. overflow handler and abort handler are also in here.
*/ */
/* /*
@ -95,15 +95,29 @@ inline static void panicPutHex(int a) { }
inline static void panicPutDec(int a) { } inline static void panicPutDec(int a) { }
#endif #endif
void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName ) void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName )
{ {
panicPutStr("***ERROR*** A stack overflow in task "); panicPutStr("***ERROR*** A stack overflow in task ");
panicPutStr((char *)pcTaskName); panicPutStr((char *)pcTaskName);
panicPutStr(" has been detected.\r\n"); panicPutStr(" has been detected.\r\n");
configASSERT(0); abort();
} }
static bool abort_called;
void abort()
{
#if !CONFIG_ESP32_PANIC_SILENT_REBOOT
ets_printf("abort() was called at PC 0x%08x\n", (intptr_t)__builtin_return_address(0) - 3);
#endif
abort_called = true;
while(1) {
__asm__ ("break 0,0");
*((int*) 0) = 0;
}
}
static const char *edesc[] = { static const char *edesc[] = {
"IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError", "IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError",
"Level1Interrupt", "Alloca", "IntegerDivideByZero", "PCValue", "Level1Interrupt", "Alloca", "IntegerDivideByZero", "PCValue",
@ -118,7 +132,7 @@ static const char *edesc[] = {
}; };
void commonErrorHandler(XtExcFrame *frame); static void commonErrorHandler(XtExcFrame *frame);
//The fact that we've panic'ed probably means the other CPU is now running wild, possibly //The fact that we've panic'ed probably means the other CPU is now running wild, possibly
//messing up the serial output, so we stall it here. //messing up the serial output, so we stall it here.
@ -127,19 +141,6 @@ static void haltOtherCore()
esp_cpu_stall( xPortGetCoreID() == 0 ? 1 : 0 ); esp_cpu_stall( xPortGetCoreID() == 0 ? 1 : 0 );
} }
//Returns true when a debugger is attached using JTAG.
static int inOCDMode()
{
#if CONFIG_ESP32_DEBUG_OCDAWARE
int dcr;
int reg = 0x10200C; //DSRSET register
asm("rer %0,%1":"=r"(dcr):"r"(reg));
return (dcr & 0x1);
#else
return 0; //Always return no debugger is attached.
#endif
}
void panicHandler(XtExcFrame *frame) void panicHandler(XtExcFrame *frame)
{ {
int *regs = (int *)frame; int *regs = (int *)frame;
@ -165,7 +166,7 @@ void panicHandler(XtExcFrame *frame)
panicPutStr(reason); panicPutStr(reason);
panicPutStr(")\r\n"); panicPutStr(")\r\n");
if (inOCDMode()) { if (esp_cpu_in_ocd_debug_mode()) {
asm("break.n 1"); asm("break.n 1");
} }
commonErrorHandler(frame); commonErrorHandler(frame);
@ -197,7 +198,7 @@ void xt_unhandled_exception(XtExcFrame *frame)
} }
panicPutStr(" occurred on core "); panicPutStr(" occurred on core ");
panicPutDec(xPortGetCoreID()); panicPutDec(xPortGetCoreID());
if (inOCDMode()) { if (esp_cpu_in_ocd_debug_mode()) {
panicPutStr(" at pc="); panicPutStr(" at pc=");
panicPutHex(regs[1]); panicPutHex(regs[1]);
panicPutStr(". Setting bp and returning..\r\n"); panicPutStr(". Setting bp and returning..\r\n");
@ -255,6 +256,7 @@ static inline bool stackPointerIsSane(uint32_t sp)
{ {
return !(sp < 0x3ffae010 || sp > 0x3ffffff0 || ((sp & 0xf) != 0)); return !(sp < 0x3ffae010 || sp > 0x3ffffff0 || ((sp & 0xf) != 0));
} }
static void putEntry(uint32_t pc, uint32_t sp) static void putEntry(uint32_t pc, uint32_t sp)
{ {
if (pc & 0x80000000) { if (pc & 0x80000000) {
@ -265,7 +267,8 @@ static void putEntry(uint32_t pc, uint32_t sp)
panicPutStr(":0x"); panicPutStr(":0x");
panicPutHex(sp); panicPutHex(sp);
} }
void doBacktrace(XtExcFrame *frame)
static void doBacktrace(XtExcFrame *frame)
{ {
uint32_t i = 0, pc = frame->pc, sp = frame->a1; uint32_t i = 0, pc = frame->pc, sp = frame->a1;
panicPutStr("\nBacktrace:"); panicPutStr("\nBacktrace:");
@ -291,7 +294,7 @@ void doBacktrace(XtExcFrame *frame)
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.
*/ */
void commonErrorHandler(XtExcFrame *frame) static void commonErrorHandler(XtExcFrame *frame)
{ {
int *regs = (int *)frame; int *regs = (int *)frame;
int x, y; int x, y;
@ -304,21 +307,28 @@ void commonErrorHandler(XtExcFrame *frame)
//Feed the watchdogs, so they will give us time to print out debug info //Feed the watchdogs, so they will give us time to print out debug info
reconfigureAllWdts(); reconfigureAllWdts();
panicPutStr("Register dump:\r\n"); /* only dump registers for 'real' crashes, if crashing via abort()
the register window is no longer useful.
*/
if (!abort_called) {
panicPutStr("Register dump:\r\n");
for (x = 0; x < 24; x += 4) { for (x = 0; x < 24; x += 4) {
for (y = 0; y < 4; y++) { for (y = 0; y < 4; y++) {
if (sdesc[x + y][0] != 0) { if (sdesc[x + y][0] != 0) {
panicPutStr(sdesc[x + y]); panicPutStr(sdesc[x + y]);
panicPutStr(": 0x"); panicPutStr(": 0x");
panicPutHex(regs[x + y + 1]); panicPutHex(regs[x + y + 1]);
panicPutStr(" "); panicPutStr(" ");
}
} }
panicPutStr("\r\n");
} }
panicPutStr("\r\n");
} }
/* With windowed ABI backtracing is easy, let's do it. */ /* With windowed ABI backtracing is easy, let's do it. */
doBacktrace(frame); doBacktrace(frame);
#if CONFIG_ESP32_PANIC_GDBSTUB #if CONFIG_ESP32_PANIC_GDBSTUB
disableAllWdts(); disableAllWdts();
panicPutStr("Entering gdb stub now.\r\n"); panicPutStr("Entering gdb stub now.\r\n");
@ -339,8 +349,7 @@ void commonErrorHandler(XtExcFrame *frame)
void esp_set_breakpoint_if_jtag(void *fn) void esp_set_breakpoint_if_jtag(void *fn)
{ {
if (!inOCDMode()) { if (esp_cpu_in_ocd_debug_mode()) {
return; setFirstBreakpoint((uint32_t)fn);
} }
setFirstBreakpoint((uint32_t)fn);
} }

View File

@ -22,15 +22,6 @@
#include "esp_attr.h" #include "esp_attr.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
void IRAM_ATTR abort()
{
do
{
__asm__ ("break 0,0");
*((int*) 0) = 0;
} while(true);
}
void* IRAM_ATTR _malloc_r(struct _reent *r, size_t size) void* IRAM_ATTR _malloc_r(struct _reent *r, size_t size)
{ {
return pvPortMalloc(size); return pvPortMalloc(size);