28
28
#include "esp8266_peri.h"
29
29
#include "cont.h"
30
30
#include "pgmspace.h"
31
+ #include "gdb_hooks.h"
31
32
32
33
extern void __real_system_restart_local ();
33
- extern void gdb_do_break ();
34
34
35
35
extern cont_t g_cont ;
36
36
37
37
// These will be pointers to PROGMEM const strings
38
38
static const char * s_panic_file = 0 ;
39
39
static int s_panic_line = 0 ;
40
40
static const char * s_panic_func = 0 ;
41
+ static const char * s_panic_what = 0 ;
41
42
42
43
static bool s_abort_called = false;
43
44
44
- void uart_write_char_d (char c );
45
+ void abort () __attribute__((noreturn ));
46
+ static void uart_write_char_d (char c );
45
47
static void uart0_write_char_d (char c );
46
48
static void uart1_write_char_d (char c );
47
49
static void print_stack (uint32_t start , uint32_t end );
48
- //static void print_pcs(uint32_t start, uint32_t end);
49
50
50
- bool __attribute((weak )) crash_for_gdb = 0 ;
51
+ // From UMM, the last caller of a malloc/realloc/calloc which failed:
52
+ extern void * umm_last_fail_alloc_addr ;
53
+ extern int umm_last_fail_alloc_size ;
54
+
55
+ static void raise_exception () __attribute__((noreturn ));
51
56
52
57
extern void __custom_crash_callback ( struct rst_info * rst_info , uint32_t stack , uint32_t stack_end ) {
53
58
(void ) rst_info ;
@@ -57,18 +62,42 @@ extern void __custom_crash_callback( struct rst_info * rst_info, uint32_t stack,
57
62
58
63
extern void custom_crash_callback ( struct rst_info * rst_info , uint32_t stack , uint32_t stack_end ) __attribute__ ((weak , alias ("__custom_crash_callback" )));
59
64
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
- }
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__); \
66
87
}
67
88
68
89
void __wrap_system_restart_local () {
69
- if (crash_for_gdb ) * ((int * )0 ) = 0 ;
70
90
register uint32_t sp asm("a1" );
71
91
92
+ if (gdb_present ()) {
93
+ /* When GDBStub is present, exceptions are handled by GDBStub,
94
+ but Soft WDT will still call this function.
95
+ Trigger an exception to break into GDB.
96
+ TODO: check why gdb_do_break() or asm("break.n 0") do not
97
+ break into GDB here. */
98
+ raise_exception ();
99
+ }
100
+
72
101
struct rst_info rst_info = {0 };
73
102
system_rtc_mem_read (0 , & rst_info , sizeof (rst_info ));
74
103
if (rst_info .reason != REASON_SOFT_WDT_RST &&
@@ -81,21 +110,25 @@ void __wrap_system_restart_local() {
81
110
ets_install_putc1 (& uart_write_char_d );
82
111
83
112
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" ));
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' );
89
122
}
90
123
else if (s_abort_called ) {
91
- ets_puts_P ( PSTR ( "Abort called\n") );
124
+ ets_printf_P ( "\nAbort called\n" );
92
125
}
93
126
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" ,
127
+ ets_printf_P ("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n" ,
95
128
rst_info .exccause , rst_info .epc1 , rst_info .epc2 , rst_info .epc3 , rst_info .excvaddr , rst_info .depc );
96
129
}
97
130
else if (rst_info .reason == REASON_SOFT_WDT_RST ) {
98
- ets_puts_P ( PSTR ( "\nSoft WDT reset\n" ) );
131
+ ets_printf_P ( "\nSoft WDT reset\n" );
99
132
}
100
133
101
134
uint32_t cont_stack_start = (uint32_t ) & (g_cont .stack );
@@ -117,60 +150,47 @@ void __wrap_system_restart_local() {
117
150
}
118
151
119
152
if (sp > cont_stack_start && sp < cont_stack_end ) {
120
- ets_puts_P ( PSTR ( "\nctx: cont \n" ) );
153
+ ets_printf_P ( "\nctx: cont \n" );
121
154
stack_end = cont_stack_end ;
122
155
}
123
156
else {
124
- ets_puts_P (( "\nctx: sys \n" ) );
157
+ ets_printf_P ( "\nctx: sys \n" );
125
158
stack_end = 0x3fffffb0 ;
126
159
// it's actually 0x3ffffff0, but the stuff below ets_run
127
160
// is likely not really relevant to the crash
128
161
}
129
162
130
- 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 );
131
164
132
- // print_pcs(sp + offset, stack_end);
133
165
print_stack (sp + offset , stack_end );
134
166
167
+ // Use cap-X formatting to ensure the standard EspExceptionDecoder doesn't match the address
168
+ if (umm_last_fail_alloc_addr ) {
169
+ ets_printf ("\nlast failed alloc call: %08X(%d)\n" , (uint32_t )umm_last_fail_alloc_addr , umm_last_fail_alloc_size );
170
+ }
171
+
135
172
custom_crash_callback ( & rst_info , sp + offset , stack_end );
136
173
137
174
delayMicroseconds (10000 );
138
175
__real_system_restart_local ();
139
176
}
140
177
141
178
142
- static void print_stack (uint32_t start , uint32_t end ) {
143
- 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" );
144
181
for (uint32_t pos = start ; pos < end ; pos += 0x10 ) {
145
182
uint32_t * values = (uint32_t * )(pos );
146
183
147
184
// rough indicator: stack frames usually have SP saved as the second word
148
185
bool looksLikeStackFrame = (values [2 ] == pos + 0x10 );
149
186
150
- ets_printf ("%08x: %08x %08x %08x %08x %c\n" ,
187
+ ets_printf_P ("%08x: %08x %08x %08x %08x %c\n" ,
151
188
pos , values [0 ], values [1 ], values [2 ], values [3 ], (looksLikeStackFrame )?'<' :' ' );
152
189
}
153
- ets_puts_P ( PSTR ( "<<<stack<<<\n" ) );
190
+ ets_printf_P ( "<<<stack<<<\n" );
154
191
}
155
192
156
- /*
157
- static void print_pcs(uint32_t start, uint32_t end) {
158
- uint32_t n = 0;
159
- ets_printf("\n>>>pc>>>\n");
160
- for (uint32_t pos = start; pos < end; pos += 16, ++n) {
161
- uint32_t* sf = (uint32_t*) pos;
162
-
163
- uint32_t pc_ret = sf[3];
164
- uint32_t sp_ret = sf[2];
165
- if (pc_ret < 0x40000000 || pc_ret > 0x40f00000 || sp_ret != pos + 16)
166
- continue;
167
- ets_printf("%08x\n", pc_ret);
168
- }
169
- ets_printf("<<<pc<<<\n");
170
- }
171
- */
172
-
173
- void uart_write_char_d (char c ) {
193
+ static void uart_write_char_d (char c ) {
174
194
uart0_write_char_d (c );
175
195
uart1_write_char_d (c );
176
196
}
@@ -192,29 +212,32 @@ static void uart1_write_char_d(char c) {
192
212
}
193
213
USF (1 ) = c ;
194
214
}
195
- void abort () __attribute__((noreturn ));
196
215
197
- void abort (){
198
- // cause exception
216
+ static void raise_exception () {
217
+ __asm__ __volatile__ ("syscall" );
218
+ while (1 ); // never reached, needed to satisfy "noreturn" attribute
219
+ }
220
+
221
+ void abort () {
199
222
s_abort_called = true;
200
- do {
201
- * ((int * )0 ) = 0 ;
202
- } while (true);
223
+ raise_exception ();
203
224
}
204
225
205
226
void __assert_func (const char * file , int line , const char * func , const char * what ) {
206
- (void ) what ;
207
227
s_panic_file = file ;
208
228
s_panic_line = line ;
209
229
s_panic_func = func ;
210
- gdb_do_break ();
230
+ s_panic_what = what ;
231
+ gdb_do_break (); /* if GDB is not present, this is a no-op */
232
+ raise_exception ();
211
233
}
212
234
213
235
void __panic_func (const char * file , int line , const char * func ) {
214
236
s_panic_file = file ;
215
237
s_panic_line = line ;
216
238
s_panic_func = func ;
217
- gdb_do_break ();
218
- abort ();
239
+ s_panic_what = 0 ;
240
+ gdb_do_break (); /* if GDB is not present, this is a no-op */
241
+ raise_exception ();
219
242
}
220
243
0 commit comments