Merge branch 'feature/backtrace_dumps' into 'master'

Feature/backtrace dumps

Github pull request https://github.com/espressif/esp-idf/pull/149

(Plus reformatting of panic.c, as it hadn't been formatted to our code style yet.)

See merge request !290
This commit is contained in:
Angus Gratton
2016-12-08 13:27:33 +08:00
2 changed files with 236 additions and 168 deletions

View File

@@ -45,48 +45,59 @@ Note: The linker script will put everything in this file in IRAM/DRAM, so it als
#if !CONFIG_ESP32_PANIC_SILENT_REBOOT #if !CONFIG_ESP32_PANIC_SILENT_REBOOT
//printf may be broken, so we fix our own printing fns... //printf may be broken, so we fix our own printing fns...
inline static void panicPutchar(char c) { inline static void panicPutChar(char c)
{
while (((READ_PERI_REG(UART_STATUS_REG(0)) >> UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT) >= 126) ; while (((READ_PERI_REG(UART_STATUS_REG(0)) >> UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT) >= 126) ;
WRITE_PERI_REG(UART_FIFO_REG(0), c); WRITE_PERI_REG(UART_FIFO_REG(0), c);
} }
inline static void panicPutStr(const char *c) { inline static void panicPutStr(const char *c)
{
int x = 0; int x = 0;
while (c[x] != 0) { while (c[x] != 0) {
panicPutchar(c[x]); panicPutChar(c[x]);
x++; x++;
} }
} }
inline static void panicPutHex(int a) { inline static void panicPutHex(int a)
{
int x; int x;
int c; int c;
panicPutchar(' ');
for (x = 0; x < 8; x++) { for (x = 0; x < 8; x++) {
c = (a >> 28) & 0xf; c = (a >> 28) & 0xf;
if (c<10) panicPutchar('0'+c); else panicPutchar('a'+c-10); if (c < 10) {
panicPutChar('0' + c);
} else {
panicPutChar('a' + c - 10);
}
a <<= 4; a <<= 4;
} }
} }
inline static void panicPutDec(int a) { inline static void panicPutDec(int a)
{
int n1, n2; int n1, n2;
n1 = a % 10; n1 = a % 10;
n2 = a / 10; n2 = a / 10;
panicPutchar(' '); if (n2 == 0) {
if (n2==0) panicPutchar(' '); else panicPutchar(n2+'0'); panicPutChar(' ');
panicPutchar(n1+'0'); } else {
panicPutChar(n2 + '0');
}
panicPutChar(n1 + '0');
} }
#else #else
//No printing wanted. Stub out these functions. //No printing wanted. Stub out these functions.
inline static void panicPutchar(char c) { } inline static void panicPutChar(char c) { }
inline static void panicPutStr(const char *c) { } inline static void panicPutStr(const char *c) { }
inline static void panicPutHex(int a) { } 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");
@@ -117,7 +128,8 @@ static void haltOtherCore()
} }
//Returns true when a debugger is attached using JTAG. //Returns true when a debugger is attached using JTAG.
static int inOCDMode() { static int inOCDMode()
{
#if CONFIG_ESP32_DEBUG_OCDAWARE #if CONFIG_ESP32_DEBUG_OCDAWARE
int dcr; int dcr;
int reg = 0x10200C; //DSRSET register int reg = 0x10200C; //DSRSET register
@@ -128,7 +140,8 @@ static int inOCDMode() {
#endif #endif
} }
void panicHandler(XtExcFrame *frame) { void panicHandler(XtExcFrame *frame)
{
int *regs = (int *)frame; int *regs = (int *)frame;
//Please keep in sync with PANIC_RSN_* defines //Please keep in sync with PANIC_RSN_* defines
const char *reasons[] = { const char *reasons[] = {
@@ -142,7 +155,9 @@ void panicHandler(XtExcFrame *frame) {
}; };
const char *reason = reasons[0]; const char *reason = reasons[0];
//The panic reason is stored in the EXCCAUSE register. //The panic reason is stored in the EXCCAUSE register.
if (regs[20]<=PANIC_RSN_MAX) reason=reasons[regs[20]]; if (regs[20] <= PANIC_RSN_MAX) {
reason = reasons[regs[20]];
}
haltOtherCore(); haltOtherCore();
panicPutStr("Guru Meditation Error: Core "); panicPutStr("Guru Meditation Error: Core ");
panicPutDec(xPortGetCoreID()); panicPutDec(xPortGetCoreID());
@@ -156,7 +171,8 @@ void panicHandler(XtExcFrame *frame) {
commonErrorHandler(frame); commonErrorHandler(frame);
} }
static void setFirstBreakpoint(uint32_t pc) { static void setFirstBreakpoint(uint32_t pc)
{
asm( asm(
"wsr.ibreaka0 %0\n" \ "wsr.ibreaka0 %0\n" \
"rsr.ibreakenable a3\n" \ "rsr.ibreakenable a3\n" \
@@ -166,14 +182,19 @@ static void setFirstBreakpoint(uint32_t pc) {
::"r"(pc):"a3", "a4"); ::"r"(pc):"a3", "a4");
} }
void xt_unhandled_exception(XtExcFrame *frame) { void xt_unhandled_exception(XtExcFrame *frame)
{
int *regs = (int *)frame; int *regs = (int *)frame;
int x; int x;
haltOtherCore(); haltOtherCore();
panicPutStr("Guru Meditation Error of type "); panicPutStr("Guru Meditation Error of type ");
x = regs[20]; x = regs[20];
if (x<40) panicPutStr(edesc[x]); else panicPutStr("Unknown"); if (x < 40) {
panicPutStr(edesc[x]);
} else {
panicPutStr("Unknown");
}
panicPutStr(" occurred on core "); panicPutStr(" occurred on core ");
panicPutDec(xPortGetCoreID()); panicPutDec(xPortGetCoreID());
if (inOCDMode()) { if (inOCDMode()) {
@@ -197,7 +218,8 @@ the risk of somehow halting in the panic handler and not resetting. That is why
all watchdogs except the timer group 0 watchdog, and it reconfigures that to reset the chip after all watchdogs except the timer group 0 watchdog, and it reconfigures that to reset the chip after
one second. one second.
*/ */
static void reconfigureAllWdts() { static void reconfigureAllWdts()
{
TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
TIMERG0.wdt_feed = 1; TIMERG0.wdt_feed = 1;
TIMERG0.wdt_config0.sys_reset_length = 7; //3.2uS TIMERG0.wdt_config0.sys_reset_length = 7; //3.2uS
@@ -217,7 +239,8 @@ static void reconfigureAllWdts() {
/* /*
This disables all the watchdogs for when we call the gdbstub. This disables all the watchdogs for when we call the gdbstub.
*/ */
static void disableAllWdts() { static void disableAllWdts()
{
TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
TIMERG0.wdt_config0.en = 0; TIMERG0.wdt_config0.en = 0;
TIMERG0.wdt_wprotect = 0; TIMERG0.wdt_wprotect = 0;
@@ -228,17 +251,55 @@ static void disableAllWdts() {
#endif #endif
static inline bool stackPointerIsSane(uint32_t sp)
{
return !(sp < 0x3ffae010 || sp > 0x3ffffff0 || ((sp & 0xf) != 0));
}
static void putEntry(uint32_t pc, uint32_t sp)
{
if (pc & 0x80000000) {
pc = (pc & 0x3fffffff) | 0x40000000;
}
panicPutStr(" 0x");
panicPutHex(pc);
panicPutStr(":0x");
panicPutHex(sp);
}
void doBacktrace(XtExcFrame *frame)
{
uint32_t i = 0, pc = frame->pc, sp = frame->a1;
panicPutStr("\nBacktrace:");
/* Do not check sanity on first entry, PC could be smashed. */
putEntry(pc, sp);
pc = frame->a0;
while (i++ < 100) {
uint32_t psp = sp;
if (!stackPointerIsSane(sp) || i++ > 100) {
break;
}
sp = *((uint32_t *) (sp - 0x10 + 4));
putEntry(pc, sp);
pc = *((uint32_t *) (psp - 0x10));
if (pc < 0x40000000) {
break;
}
}
panicPutStr("\n\n");
}
/* /*
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) { void commonErrorHandler(XtExcFrame *frame)
{
int *regs = (int *)frame; int *regs = (int *)frame;
int x, y; int x, y;
const char *sdesc[] = { const char *sdesc[] = {
"PC ", "PS ", "A0 ", "A1 ", "A2 ", "A3 ", "A4 ", "A5 ", "PC ", "PS ", "A0 ", "A1 ", "A2 ", "A3 ", "A4 ", "A5 ",
"A6 ", "A7 ", "A8 ", "A9 ", "A10 ", "A11 ", "A12 ", "A13 ", "A6 ", "A7 ", "A8 ", "A9 ", "A10 ", "A11 ", "A12 ", "A13 ",
"A14 ","A15 ","SAR ","EXCCAUSE","EXCVADDR","LBEG ","LEND ","LCOUNT "}; "A14 ", "A15 ", "SAR ", "EXCCAUSE", "EXCVADDR", "LBEG ", "LEND ", "LCOUNT "
};
//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();
@@ -249,20 +310,24 @@ void commonErrorHandler(XtExcFrame *frame) {
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(": "); 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. */
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");
esp_gdbstub_panic_handler(frame); esp_gdbstub_panic_handler(frame);
#elif CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT #elif CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
panicPutStr("Rebooting...\r\n"); panicPutStr("Rebooting...\r\n");
for (x=0; x<100; x++) ets_delay_us(1000); for (x = 0; x < 100; x++) {
ets_delay_us(1000);
}
software_reset(); software_reset();
#else #else
disableAllWdts(); disableAllWdts();
@@ -272,7 +337,10 @@ void commonErrorHandler(XtExcFrame *frame) {
} }
void esp_set_breakpoint_if_jtag(void *fn) { void esp_set_breakpoint_if_jtag(void *fn)
if (!inOCDMode()) return; {
if (!inOCDMode()) {
return;
}
setFirstBreakpoint((uint32_t)fn); setFirstBreakpoint((uint32_t)fn);
} }

0
tools/format.sh Normal file → Executable file
View File