Skip to content

Commit f6a3c32

Browse files
Fix exception handler, add assert, reduce RAM
Move all exception strings to IRAM and out of both PMEM (illegal) and add output of any assert() failinf conditions. The exception handler may be called while the SPI interface is in a bad state. This means no PROGMEM reads are allowed, and all data and functions used must be in system RAM or IRAM. Add a new helper macro, ets_printf_P(), which places a constant string in IRAM and copies it to the stack before calling the real ets_printf(). This makes the code simpler to read as no unwieldy combinations of ets_putc/ets_printf/... are required to output anything. The old handler also mistakenly used PSTR() strings in some places, so fix those with this patch as well. Gives back ~180 bytes of heap to every sketch built as the exception handler is always included an application.
1 parent b08ff10 commit f6a3c32

File tree

2 files changed

+49
-28
lines changed

2 files changed

+49
-28
lines changed

cores/esp8266/core_esp8266_postmortem.c

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ extern cont_t g_cont;
3838
static const char* s_panic_file = 0;
3939
static int s_panic_line = 0;
4040
static const char* s_panic_func = 0;
41+
static const char* s_panic_what = 0;
4142

4243
static bool s_abort_called = false;
4344

@@ -57,18 +58,33 @@ extern void __custom_crash_callback( struct rst_info * rst_info, uint32_t stack,
5758

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

60-
static void ets_puts_P(const char *romString) {
61-
char c = pgm_read_byte(romString++);
62-
while (c) {
63-
ets_putc(c);
64-
c = pgm_read_byte(romString++);
65-
}
61+
// Single, non-inlined copy of pgm_read_byte to save IRAM space (as this is not timing critical)
62+
static char ICACHE_RAM_ATTR iram_read_byte (const char *addr) {
63+
return pgm_read_byte(addr);
64+
}
65+
66+
// Required to output the s_panic_file, it's stored in PMEM
67+
#define ets_puts_P(pstr) \
68+
{ \
69+
char c; \
70+
do { \
71+
c = iram_read_byte(pstr++); \
72+
if (c) ets_putc(c); \
73+
} while (c); \
74+
}
75+
76+
// Place these strings in .text because the SPI interface may be in bad shape during an exception.
77+
#define ets_printf_P(str, ...) \
78+
{ \
79+
static const char istr[] ICACHE_RAM_ATTR = (str); \
80+
char mstr[sizeof(str)]; \
81+
for (size_t i=0; i < sizeof(str); i++) mstr[i] = iram_read_byte(&istr[i]); \
82+
ets_printf(mstr, ##__VA_ARGS__); \
6683
}
6784

6885
void __wrap_system_restart_local() {
6986
if (crash_for_gdb) *((int*)0) = 0;
7087
register uint32_t sp asm("a1");
71-
7288
struct rst_info rst_info = {0};
7389
system_rtc_mem_read(0, &rst_info, sizeof(rst_info));
7490
if (rst_info.reason != REASON_SOFT_WDT_RST &&
@@ -81,21 +97,25 @@ void __wrap_system_restart_local() {
8197
ets_install_putc1(&uart_write_char_d);
8298

8399
if (s_panic_line) {
84-
ets_puts_P(PSTR("\nPanic "));
85-
ets_puts_P(s_panic_file);
86-
ets_printf(":%d ", s_panic_line);
87-
ets_puts_P(s_panic_func);
88-
ets_puts_P(PSTR("\n"));
100+
ets_printf_P("\nPanic ");
101+
ets_puts_P(s_panic_file); // This is in PROGMEM, need special output because ets_printf can't handle ROM parameters
102+
ets_printf_P(":%d %s", s_panic_line, s_panic_func);
103+
if (s_panic_what) {
104+
ets_printf_P(": Assertion '");
105+
ets_puts_P(s_panic_what); // This is also in PMEM
106+
ets_printf_P("' failed.");
107+
}
108+
ets_putc('\n');
89109
}
90110
else if (s_abort_called) {
91-
ets_puts_P(PSTR("Abort called\n"));
111+
ets_printf_P("\nAbort called\n");
92112
}
93113
else if (rst_info.reason == REASON_EXCEPTION_RST) {
94-
ets_printf("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n",
114+
ets_printf_P("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n",
95115
rst_info.exccause, rst_info.epc1, rst_info.epc2, rst_info.epc3, rst_info.excvaddr, rst_info.depc);
96116
}
97117
else if (rst_info.reason == REASON_SOFT_WDT_RST) {
98-
ets_puts_P(PSTR("\nSoft WDT reset\n"));
118+
ets_printf_P("\nSoft WDT reset\n");
99119
}
100120

101121
uint32_t cont_stack_start = (uint32_t) &(g_cont.stack);
@@ -117,17 +137,17 @@ void __wrap_system_restart_local() {
117137
}
118138

119139
if (sp > cont_stack_start && sp < cont_stack_end) {
120-
ets_puts_P(PSTR("\nctx: cont \n"));
140+
ets_printf_P("\nctx: cont \n");
121141
stack_end = cont_stack_end;
122142
}
123143
else {
124-
ets_puts_P(("\nctx: sys \n"));
144+
ets_printf_P("\nctx: sys \n");
125145
stack_end = 0x3fffffb0;
126146
// it's actually 0x3ffffff0, but the stuff below ets_run
127147
// is likely not really relevant to the crash
128148
}
129149

130-
ets_printf("sp: %08x end: %08x offset: %04x\n", sp, stack_end, offset);
150+
ets_printf_P("sp: %08x end: %08x offset: %04x\n", sp, stack_end, offset);
131151

132152
// print_pcs(sp + offset, stack_end);
133153
print_stack(sp + offset, stack_end);
@@ -139,34 +159,34 @@ void __wrap_system_restart_local() {
139159
}
140160

141161

142-
static void print_stack(uint32_t start, uint32_t end) {
143-
ets_puts_P(PSTR("\n>>>stack>>>\n"));
162+
static void ICACHE_RAM_ATTR print_stack(uint32_t start, uint32_t end) {
163+
ets_printf_P("\n>>>stack>>>\n");
144164
for (uint32_t pos = start; pos < end; pos += 0x10) {
145165
uint32_t* values = (uint32_t*)(pos);
146166

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

150-
ets_printf("%08x: %08x %08x %08x %08x %c\n",
170+
ets_printf_P("%08x: %08x %08x %08x %08x %c\n",
151171
pos, values[0], values[1], values[2], values[3], (looksLikeStackFrame)?'<':' ');
152172
}
153-
ets_puts_P(PSTR("<<<stack<<<\n"));
173+
ets_printf_P("<<<stack<<<\n");
154174
}
155175

156176
/*
157-
static void print_pcs(uint32_t start, uint32_t end) {
177+
static void ICACHE_RAM_ATTR print_pcs(uint32_t start, uint32_t end) {
158178
uint32_t n = 0;
159-
ets_printf("\n>>>pc>>>\n");
179+
ets_printf_P("\n>>>pc>>>\n");
160180
for (uint32_t pos = start; pos < end; pos += 16, ++n) {
161181
uint32_t* sf = (uint32_t*) pos;
162182
163183
uint32_t pc_ret = sf[3];
164184
uint32_t sp_ret = sf[2];
165185
if (pc_ret < 0x40000000 || pc_ret > 0x40f00000 || sp_ret != pos + 16)
166186
continue;
167-
ets_printf("%08x\n", pc_ret);
187+
ets_printf_P("%08x\n", pc_ret);
168188
}
169-
ets_printf("<<<pc<<<\n");
189+
ets_printf_P("<<<pc<<<\n");
170190
}
171191
*/
172192

@@ -203,17 +223,18 @@ void abort(){
203223
}
204224

205225
void __assert_func(const char *file, int line, const char *func, const char *what) {
206-
(void) what;
207226
s_panic_file = file;
208227
s_panic_line = line;
209228
s_panic_func = func;
229+
s_panic_what = what;
210230
gdb_do_break();
211231
}
212232

213233
void __panic_func(const char* file, int line, const char* func) {
214234
s_panic_file = file;
215235
s_panic_line = line;
216236
s_panic_func = func;
237+
s_panic_what = 0;
217238
gdb_do_break();
218239
abort();
219240
}

tools/sdk/libc/xtensa-lx106-elf/include/assert.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ extern "C" {
1515
# define assert(__e) ((void)0)
1616
#else
1717
# define assert(__e) ((__e) ? (void)0 : __assert_func (PSTR(__FILE__), __LINE__, \
18-
__ASSERT_FUNC, #__e))
18+
__ASSERT_FUNC, PSTR(#__e)))
1919

2020
# ifndef __ASSERT_FUNC
2121
/* Use g++'s demangled names in C++. */

0 commit comments

Comments
 (0)