Skip to content

Commit

Permalink
Increase free IRAM (esp8266#5499)
Browse files Browse the repository at this point in the history
* Move functions out of IRAM when possible

umm_init() is called in OS startup after flash is enabled, and never
again.

cont_get_free_stack() shouldn't be called from IRQ.

Don't inline _iram_read_byte() function.

* Move system fault handler to flash, use new printf

The __wrap_system_restart call has been in flash for quite a while and
seems to be working fine.  There were some support routines that were
placed in IRAM (mistakenly thinking the wrap_restart caller was also in
IRAM) which are now moved to flash.

Clean up the printf code to use the new stdlib which handles PGM_P
strings as format and arguments without any difficulty.

* Make STR macro more unique

Add double-underscores to some string assistance macros to avoid
conflicts with user applications.

* Use function, not macro, to save code space

Save ~2KB final bin size by using a ets_printf_P function and not
an inline macro.  IRAM and HEAP unaffected.

* Don't actually touch the SP in the dump

Store a copy of the incoming stack pointer in the postmortem in order
to avoid actually changing the SP when a crash happend in BearSSL.

* Make C++ uncaught exceptions explicit

Use the term "Unhandled C++ exception" instead of just "Unhandled
exception" to make it clear such crashes are caused by a C++ throw
and now a system exception.
  • Loading branch information
earlephilhower authored Dec 15, 2018
1 parent 6324241 commit 8e46a33
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 56 deletions.
3 changes: 2 additions & 1 deletion cores/esp8266/cont_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ int ICACHE_RAM_ATTR cont_check(cont_t* cont) {
return 0;
}

int ICACHE_RAM_ATTR cont_get_free_stack(cont_t* cont) {
// No need for this to be in IRAM, not expected to be IRQ called
int cont_get_free_stack(cont_t* cont) {
uint32_t *head = cont->stack;
int freeWords = 0;

Expand Down
82 changes: 35 additions & 47 deletions cores/esp8266/core_esp8266_postmortem.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,32 +62,25 @@ 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")));

// 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__); \
// Prints need to use our library function to allow for file and function
// to be safely accessed from flash. This function encapsulates snprintf()
// [which by definition will 0-terminate] and dumping to the UART
static void ets_printf_P(const char *str, ...) {
char destStr[160];
char *c = destStr;
va_list argPtr;
va_start(argPtr, str);
vsnprintf(destStr, sizeof(destStr), str, argPtr);
va_end(argPtr);
while (*c) {
ets_putc(*(c++));
}
}

void __wrap_system_restart_local() {
register uint32_t sp asm("a1");
uint32_t sp_dump = sp;

if (gdb_present()) {
/* When GDBStub is present, exceptions are handled by GDBStub,
Expand All @@ -110,28 +103,24 @@ void __wrap_system_restart_local() {
ets_install_putc1(&uart_write_char_d);

if (s_panic_line) {
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);
ets_printf_P(PSTR("\nPanic %S:%d %S"), s_panic_file, 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_printf_P(PSTR(": Assertion '%S' failed."), s_panic_what);
}
ets_putc('\n');
}
else if (s_unhandled_exception) {
ets_printf_P("\nUnhandled exception: %s\n", s_unhandled_exception);
ets_printf_P(PSTR("\nUnhandled C++ exception: %S\n"), s_unhandled_exception);
}
else if (s_abort_called) {
ets_printf_P("\nAbort called\n");
ets_printf_P(PSTR("\nAbort called\n"));
}
else if (rst_info.reason == REASON_EXCEPTION_RST) {
ets_printf_P("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n",
ets_printf_P(PSTR("\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_printf_P("\nSoft WDT reset\n");
ets_printf_P(PSTR("\nSoft WDT reset\n"));
}

uint32_t cont_stack_start = (uint32_t) &(g_pcont->stack);
Expand All @@ -152,54 +141,53 @@ void __wrap_system_restart_local() {
offset = 0x10;
}

ets_printf_P("\n>>>stack>>>\n");
ets_printf_P(PSTR("\n>>>stack>>>\n"));

if (sp > stack_thunk_get_stack_bot() && sp <= stack_thunk_get_stack_top()) {
if (sp_dump > stack_thunk_get_stack_bot() && sp_dump <= stack_thunk_get_stack_top()) {
// BearSSL we dump the BSSL second stack and then reset SP back to the main cont stack
ets_printf_P("\nctx: bearssl \n");
ets_printf_P("sp: %08x end: %08x offset: %04x\n", sp, stack_thunk_get_stack_top(), offset);
print_stack(sp + offset, stack_thunk_get_stack_top());
ets_printf_P(PSTR("\nctx: bearssl\nsp: %08x end: %08x offset: %04x\n"), sp_dump, stack_thunk_get_stack_top(), offset);
print_stack(sp_dump + offset, stack_thunk_get_stack_top());
offset = 0; // No offset needed anymore, the exception info was stored in the bssl stack
sp = stack_thunk_get_cont_sp();
sp_dump = stack_thunk_get_cont_sp();
}

if (sp > cont_stack_start && sp < cont_stack_end) {
ets_printf_P("\nctx: cont \n");
if (sp_dump > cont_stack_start && sp_dump < cont_stack_end) {
ets_printf_P(PSTR("\nctx: cont\n"));
stack_end = cont_stack_end;
}
else {
ets_printf_P("\nctx: sys \n");
ets_printf_P(PSTR("\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_P("sp: %08x end: %08x offset: %04x\n", sp, stack_end, offset);
ets_printf_P(PSTR("sp: %08x end: %08x offset: %04x\n"), sp_dump, stack_end, offset);

print_stack(sp + offset, stack_end);
print_stack(sp_dump + offset, stack_end);

ets_printf_P("<<<stack<<<\n");
ets_printf_P(PSTR("<<<stack<<<\n"));

// Use cap-X formatting to ensure the standard EspExceptionDecoder doesn't match the address
if (umm_last_fail_alloc_addr) {
ets_printf_P("\nlast failed alloc call: %08X(%d)\n", (uint32_t)umm_last_fail_alloc_addr, umm_last_fail_alloc_size);
ets_printf_P(PSTR("\nlast failed alloc call: %08X(%d)\n"), (uint32_t)umm_last_fail_alloc_addr, umm_last_fail_alloc_size);
}

custom_crash_callback( &rst_info, sp + offset, stack_end );
custom_crash_callback( &rst_info, sp_dump + offset, stack_end );

delayMicroseconds(10000);
__real_system_restart_local();
}


static void ICACHE_RAM_ATTR print_stack(uint32_t start, uint32_t end) {
static void print_stack(uint32_t start, uint32_t end) {
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_P("%08x: %08x %08x %08x %08x %c\n",
ets_printf_P(PSTR("%08x: %08x %08x %08x %08x %c\n"),
pos, values[0], values[1], values[2], values[3], (looksLikeStackFrame)?'<':' ');
}
}
Expand Down
12 changes: 6 additions & 6 deletions cores/esp8266/core_esp8266_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@

#include <core_version.h>

#define STRHELPER(x) #x
#define STR(x) STRHELPER(x)
#define __STRHELPER(x) #x
#define __STR(x) __STRHELPER(x)

#ifdef __cplusplus
extern "C++"
Expand Down Expand Up @@ -111,7 +111,7 @@ namespace esp8266 {
constexpr
int coreVersionMajor ()
{
return conststr::parseNthInteger(STR(ARDUINO_ESP8266_GIT_DESC), 0);
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 0);
}

/*
Expand All @@ -120,7 +120,7 @@ int coreVersionMajor ()
constexpr
int coreVersionMinor ()
{
return conststr::parseNthInteger(STR(ARDUINO_ESP8266_GIT_DESC), 1);
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 1);
}

/*
Expand All @@ -129,7 +129,7 @@ int coreVersionMinor ()
constexpr
int coreVersionRevision ()
{
return conststr::parseNthInteger(STR(ARDUINO_ESP8266_GIT_DESC), 2);
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 2);
}

/*
Expand All @@ -139,7 +139,7 @@ int coreVersionRevision ()
constexpr
int coreVersionSubRevision ()
{
return conststr::parseNthInteger(STR(ARDUINO_ESP8266_GIT_DESC), 3);
return conststr::parseNthInteger(__STR(ARDUINO_ESP8266_GIT_DESC), 3);
}

/*
Expand Down
5 changes: 3 additions & 2 deletions cores/esp8266/umm_malloc/umm_malloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1202,8 +1202,9 @@ static unsigned short int umm_assimilate_down( unsigned short int c, unsigned sh
}

/* ------------------------------------------------------------------------- */

void umm_init( void ) {
/* This function called only one time during OS startup after flash is */
/* enabled. No need to keep it in IRAM. */
void ICACHE_FLASH_ATTR umm_init( void ) {
/* init heap pointer and size, and memset it to 0 */
umm_heap = (umm_block *)UMM_MALLOC_CFG__HEAP_ADDR;
umm_numblocks = (UMM_MALLOC_CFG__HEAP_SIZE / sizeof(umm_block));
Expand Down

0 comments on commit 8e46a33

Please sign in to comment.