Skip to content

Commit 855b03c

Browse files
earlephilhowerigrr
authored andcommitted
Fix exception handler, add assert, reduce RAM (#4187)
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 4e2e1f2 commit 855b03c

File tree

2 files changed

+46
-23
lines changed

2 files changed

+46
-23
lines changed

cores/esp8266/core_esp8266_postmortem.c

+45-22
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ 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;
42+
4143
static bool s_abort_called = false;
4244

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

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

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

7189
void __wrap_system_restart_local() {
@@ -92,21 +110,25 @@ void __wrap_system_restart_local() {
92110
ets_install_putc1(&uart_write_char_d);
93111

94112
if (s_panic_line) {
95-
ets_puts_P(PSTR("\nPanic "));
96-
ets_puts_P(s_panic_file);
97-
ets_printf(":%d ", s_panic_line);
98-
ets_puts_P(s_panic_func);
99-
ets_puts_P(PSTR("\n"));
113+
ets_printf_P("\nPanic ");
114+
ets_puts_P(s_panic_file); // This is in PROGMEM, need special output because ets_printf can't handle ROM parameters
115+
ets_printf_P(":%d %s", s_panic_line, s_panic_func);
116+
if (s_panic_what) {
117+
ets_printf_P(": Assertion '");
118+
ets_puts_P(s_panic_what); // This is also in PMEM
119+
ets_printf_P("' failed.");
120+
}
121+
ets_putc('\n');
100122
}
101123
else if (s_abort_called) {
102-
ets_puts_P(PSTR("Abort called\n"));
124+
ets_printf_P("\nAbort called\n");
103125
}
104126
else if (rst_info.reason == REASON_EXCEPTION_RST) {
105-
ets_printf("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n",
127+
ets_printf_P("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n",
106128
rst_info.exccause, rst_info.epc1, rst_info.epc2, rst_info.epc3, rst_info.excvaddr, rst_info.depc);
107129
}
108130
else if (rst_info.reason == REASON_SOFT_WDT_RST) {
109-
ets_puts_P(PSTR("\nSoft WDT reset\n"));
131+
ets_printf_P("\nSoft WDT reset\n");
110132
}
111133

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

130152
if (sp > cont_stack_start && sp < cont_stack_end) {
131-
ets_puts_P(PSTR("\nctx: cont \n"));
153+
ets_printf_P("\nctx: cont \n");
132154
stack_end = cont_stack_end;
133155
}
134156
else {
135-
ets_puts_P(("\nctx: sys \n"));
157+
ets_printf_P("\nctx: sys \n");
136158
stack_end = 0x3fffffb0;
137159
// it's actually 0x3ffffff0, but the stuff below ets_run
138160
// is likely not really relevant to the crash
139161
}
140162

141-
ets_printf("sp: %08x end: %08x offset: %04x\n", sp, stack_end, offset);
163+
ets_printf_P("sp: %08x end: %08x offset: %04x\n", sp, stack_end, offset);
142164

143165
print_stack(sp + offset, stack_end);
144166

@@ -154,18 +176,18 @@ void __wrap_system_restart_local() {
154176
}
155177

156178

157-
static void print_stack(uint32_t start, uint32_t end) {
158-
ets_puts_P(PSTR("\n>>>stack>>>\n"));
179+
static void ICACHE_RAM_ATTR print_stack(uint32_t start, uint32_t end) {
180+
ets_printf_P("\n>>>stack>>>\n");
159181
for (uint32_t pos = start; pos < end; pos += 0x10) {
160182
uint32_t* values = (uint32_t*)(pos);
161183

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

165-
ets_printf("%08x: %08x %08x %08x %08x %c\n",
187+
ets_printf_P("%08x: %08x %08x %08x %08x %c\n",
166188
pos, values[0], values[1], values[2], values[3], (looksLikeStackFrame)?'<':' ');
167189
}
168-
ets_puts_P(PSTR("<<<stack<<<\n"));
190+
ets_printf_P("<<<stack<<<\n");
169191
}
170192

171193
static void uart_write_char_d(char c) {
@@ -202,10 +224,10 @@ void abort() {
202224
}
203225

204226
void __assert_func(const char *file, int line, const char *func, const char *what) {
205-
(void) what;
206227
s_panic_file = file;
207228
s_panic_line = line;
208229
s_panic_func = func;
230+
s_panic_what = what;
209231
gdb_do_break(); /* if GDB is not present, this is a no-op */
210232
raise_exception();
211233
}
@@ -214,6 +236,7 @@ void __panic_func(const char* file, int line, const char* func) {
214236
s_panic_file = file;
215237
s_panic_line = line;
216238
s_panic_func = func;
239+
s_panic_what = 0;
217240
gdb_do_break(); /* if GDB is not present, this is a no-op */
218241
raise_exception();
219242
}

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

+1-1
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)