I was missing that too
I found valuable informations into Arduino and Sming code
also Espressif esp-gdbstub (
https://github.com/espressif/esp-gdbstub)
and Cesanta's blog (
https://backend.cesanta.com/blog/esp8266-gdb.shtml)
are totally worth a reading
then I found that xtensa provide a weak symbol for system restart
so I used that for hijacking exceptions and watchdog triggers
and save relevant information from the stack to RTC memory (that's persistent)
some code below
Code: Select all// there is a weak symbol for system_restart_hook
// into libmain.a
// 00000338 W system_restart_hook
//
// that in the assemly file shows up like this:
//
// 4022ea90 <system_restart_hook>:
// 4022ea90: f00d ret.n
// 4022ea92: ff0000 excw
// 4022ea95: ffff00 excw
// 4022ea98: 07a120 excw
//
// the following will override the weak symbol to dump relevant stack content
// in case of an exception or software watchdog trigger
// following informations will e saved to RTC memory
// - stack pointer
// - stack content that likely refer to code address (PC return address)
//
void system_restart_hook()
{
struct rst_info reset_info;
// SDK APIs for obtaining rst_info does not work...
// so copying from RTC memory (credits to Sming's guys)
system_rtc_mem_read(0, &reset_info, sizeof(reset_info));
uint32_t sp_offset = 0;
switch (reset_info.reason)
{
case REASON_SOFT_WDT_RST:
sp_offset = 0xF4;
break;
case REASON_EXCEPTION_RST:
sp_offset = 0xC0;
break;
case REASON_WDT_RST: // would have liked this one too, but it's not working
case REASON_DEFAULT_RST:
case REASON_SOFT_RESTART:
case REASON_DEEP_SLEEP_AWAKE:
case REASON_EXT_SYS_RST:
default:
return;
}
uint32_t idx;
uint32_t stack_pointer;
uint32_t rtc_ptr;
uint32_t rtc_ptr_blank = 0;
// use without offset to find the sp_offset ...
// stack_pointer = (uint32_t)&reset_info;
stack_pointer = (uint32_t)&reset_info + sp_offset;
rtc_ptr = RTC_STACKDUMP;
// save to RTC memory
// start saving the stack pointer
system_rtc_mem_write(rtc_ptr, (void *)&stack_pointer, 4);
rtc_ptr++;
fs_printf("exception epc->0x%X\n", reset_info.epc1);
fs_printf("stack dump SP->0x%X\n", stack_pointer);
fs_printf("address content\n");
for (idx = 0; idx < STACK_TRACE_LEN; idx++)
{
// using 0x3FFFFFF0 as the highest stack pointer address
if (stack_pointer > 0x3FFFFFF0)
break;
// serial log
fs_printf("%X %X", stack_pointer, *((uint32_t *)stack_pointer));
if (*((uint32_t *)stack_pointer) == reset_info.epc1)
// this is for finding the sp_offset
fs_printf(" <------ %X\n", (stack_pointer - (uint32_t)&reset_info));
else
fs_printf("\n");
// save to RTC memory
// save only stack content that possibly refers to code address
// (the 'return address')
// save up to RTC_STACKDUMP_LEN
if ((*((uint32_t *)stack_pointer) >= 0x40200000) &&
((rtc_ptr - RTC_STACKDUMP) < RTC_STACKDUMP_LEN))
{
system_rtc_mem_write(rtc_ptr, (void *)stack_pointer, 4);
rtc_ptr++;
}
stack_pointer += 4;
}
// save to RTC memory
// fill up any remaining stack trace with 0
while ((rtc_ptr - RTC_STACKDUMP) < RTC_STACKDUMP_LEN)
{
system_rtc_mem_write(rtc_ptr, (void *)&rtc_ptr_blank, 4);
rtc_ptr++;
}
}