Skip to content
67 changes: 45 additions & 22 deletions cores/esp8266/core_esp8266_postmortem.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ extern cont_t g_cont;
static const char* s_panic_file = 0;
static int s_panic_line = 0;
static const char* s_panic_func = 0;
static const char* s_panic_what = 0;

static bool s_abort_called = false;

void abort() __attribute__((noreturn));
Expand All @@ -60,12 +62,28 @@ extern void __custom_crash_callback( struct rst_info * rst_info, uint32_t stack,

extern void custom_crash_callback( struct rst_info * rst_info, uint32_t stack, uint32_t stack_end ) __attribute__ ((weak, alias("__custom_crash_callback")));

static void ets_puts_P(const char *romString) {
char c = pgm_read_byte(romString++);
while (c) {
ets_putc(c);
c = pgm_read_byte(romString++);
}
// Single, non-inlined copy of pgm_read_byte to save IRAM space (as this is not timing critical)
static char ICACHE_RAM_ATTR iram_read_byte (const char *addr) {
return pgm_read_byte(addr);
}

// Required to output the s_panic_file, it's stored in PMEM
#define ets_puts_P(pstr) \
{ \
char c; \
do { \
c = iram_read_byte(pstr++); \
if (c) ets_putc(c); \
} while (c); \
}

// Place these strings in .text because the SPI interface may be in bad shape during an exception.
#define ets_printf_P(str, ...) \
{ \
static const char istr[] ICACHE_RAM_ATTR = (str); \
char mstr[sizeof(str)]; \
for (size_t i=0; i < sizeof(str); i++) mstr[i] = iram_read_byte(&istr[i]); \
ets_printf(mstr, ##__VA_ARGS__); \
}

void __wrap_system_restart_local() {
Expand All @@ -92,21 +110,25 @@ void __wrap_system_restart_local() {
ets_install_putc1(&uart_write_char_d);

if (s_panic_line) {
ets_puts_P(PSTR("\nPanic "));
ets_puts_P(s_panic_file);
ets_printf(":%d ", s_panic_line);
ets_puts_P(s_panic_func);
ets_puts_P(PSTR("\n"));
ets_printf_P("\nPanic ");
ets_puts_P(s_panic_file); // This is in PROGMEM, need special output because ets_printf can't handle ROM parameters
ets_printf_P(":%d %s", s_panic_line, s_panic_func);
if (s_panic_what) {
ets_printf_P(": Assertion '");
ets_puts_P(s_panic_what); // This is also in PMEM
ets_printf_P("' failed.");
}
ets_putc('\n');
}
else if (s_abort_called) {
ets_puts_P(PSTR("Abort called\n"));
ets_printf_P("\nAbort called\n");
}
else if (rst_info.reason == REASON_EXCEPTION_RST) {
ets_printf("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n",
ets_printf_P("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n",
rst_info.exccause, rst_info.epc1, rst_info.epc2, rst_info.epc3, rst_info.excvaddr, rst_info.depc);
}
else if (rst_info.reason == REASON_SOFT_WDT_RST) {
ets_puts_P(PSTR("\nSoft WDT reset\n"));
ets_printf_P("\nSoft WDT reset\n");
}

uint32_t cont_stack_start = (uint32_t) &(g_cont.stack);
Expand All @@ -128,17 +150,17 @@ void __wrap_system_restart_local() {
}

if (sp > cont_stack_start && sp < cont_stack_end) {
ets_puts_P(PSTR("\nctx: cont \n"));
ets_printf_P("\nctx: cont \n");
stack_end = cont_stack_end;
}
else {
ets_puts_P(("\nctx: sys \n"));
ets_printf_P("\nctx: sys \n");
stack_end = 0x3fffffb0;
// it's actually 0x3ffffff0, but the stuff below ets_run
// is likely not really relevant to the crash
}

ets_printf("sp: %08x end: %08x offset: %04x\n", sp, stack_end, offset);
ets_printf_P("sp: %08x end: %08x offset: %04x\n", sp, stack_end, offset);

print_stack(sp + offset, stack_end);

Expand All @@ -154,18 +176,18 @@ void __wrap_system_restart_local() {
}


static void print_stack(uint32_t start, uint32_t end) {
ets_puts_P(PSTR("\n>>>stack>>>\n"));
static void ICACHE_RAM_ATTR print_stack(uint32_t start, uint32_t end) {
ets_printf_P("\n>>>stack>>>\n");
for (uint32_t pos = start; pos < end; pos += 0x10) {
uint32_t* values = (uint32_t*)(pos);

// rough indicator: stack frames usually have SP saved as the second word
bool looksLikeStackFrame = (values[2] == pos + 0x10);

ets_printf("%08x: %08x %08x %08x %08x %c\n",
ets_printf_P("%08x: %08x %08x %08x %08x %c\n",
pos, values[0], values[1], values[2], values[3], (looksLikeStackFrame)?'<':' ');
}
ets_puts_P(PSTR("<<<stack<<<\n"));
ets_printf_P("<<<stack<<<\n");
}

static void uart_write_char_d(char c) {
Expand Down Expand Up @@ -202,10 +224,10 @@ void abort() {
}

void __assert_func(const char *file, int line, const char *func, const char *what) {
(void) what;
s_panic_file = file;
s_panic_line = line;
s_panic_func = func;
s_panic_what = what;
gdb_do_break(); /* if GDB is not present, this is a no-op */
raise_exception();
}
Expand All @@ -214,6 +236,7 @@ void __panic_func(const char* file, int line, const char* func) {
s_panic_file = file;
s_panic_line = line;
s_panic_func = func;
s_panic_what = 0;
gdb_do_break(); /* if GDB is not present, this is a no-op */
raise_exception();
}
Expand Down
2 changes: 1 addition & 1 deletion tools/sdk/libc/xtensa-lx106-elf/include/assert.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ extern "C" {
# define assert(__e) ((void)0)
#else
# define assert(__e) ((__e) ? (void)0 : __assert_func (PSTR(__FILE__), __LINE__, \
__ASSERT_FUNC, #__e))
__ASSERT_FUNC, PSTR(#__e)))

# ifndef __ASSERT_FUNC
/* Use g++'s demangled names in C++. */
Expand Down