Skip to content

Commit 4ec3c81

Browse files
committed
Lite refactoring and expanded comments
lite refactoring of DEBUG_ESP_OOM printing Overall refactoring to make easier to follow. Added ABI changes includes atomic save of OOM debug info Added debug support for C++ "delete" operator Avoid identifying the wrapper code as the source of the Heap call. Each outer wrapper passes the caller's address down to the next level. Improves "caller" address reporting for OOM and Poison events. Previously, some OOM and Poison events reported info pointing to the thick heap wrapper rather than back to the caller. Update abi.cpp, heap.cpp and umm_local.c (umm_poison) to support caller parameter.
1 parent 80bf716 commit 4ec3c81

File tree

6 files changed

+587
-355
lines changed

6 files changed

+587
-355
lines changed

cores/esp8266/abi.cpp

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,57 +24,33 @@
2424
using __cxxabiv1::__guard;
2525

2626
// Debugging helper, last allocation which returned NULL
27-
extern void *umm_last_fail_alloc_addr;
28-
extern int umm_last_fail_alloc_size;
27+
extern "C" void *_heap_abi_malloc(size_t size, bool unhandle, const void* const caller);
2928

3029
extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__));
3130
extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__));
3231

33-
3432
#if !defined(__cpp_exceptions)
3533

3634
// overwrite weak operators new/new[] definitions
3735

3836
void* operator new(size_t size)
3937
{
40-
void *ret = malloc(size);
41-
if (0 != size && 0 == ret) {
42-
umm_last_fail_alloc_addr = __builtin_return_address(0);
43-
umm_last_fail_alloc_size = size;
44-
__unhandled_exception(PSTR("OOM"));
45-
}
46-
return ret;
38+
return _heap_abi_malloc(size, true, __builtin_return_address(0));
4739
}
4840

4941
void* operator new[](size_t size)
5042
{
51-
void *ret = malloc(size);
52-
if (0 != size && 0 == ret) {
53-
umm_last_fail_alloc_addr = __builtin_return_address(0);
54-
umm_last_fail_alloc_size = size;
55-
__unhandled_exception(PSTR("OOM"));
56-
}
57-
return ret;
43+
return _heap_abi_malloc(size, true, __builtin_return_address(0));
5844
}
5945

6046
void* operator new (size_t size, const std::nothrow_t&)
6147
{
62-
void *ret = malloc(size);
63-
if (0 != size && 0 == ret) {
64-
umm_last_fail_alloc_addr = __builtin_return_address(0);
65-
umm_last_fail_alloc_size = size;
66-
}
67-
return ret;
48+
return _heap_abi_malloc(size, false, __builtin_return_address(0));
6849
}
6950

7051
void* operator new[] (size_t size, const std::nothrow_t&)
7152
{
72-
void *ret = malloc(size);
73-
if (0 != size && 0 == ret) {
74-
umm_last_fail_alloc_addr = __builtin_return_address(0);
75-
umm_last_fail_alloc_size = size;
76-
}
77-
return ret;
53+
return _heap_abi_malloc(size, false, __builtin_return_address(0));
7854
}
7955

8056
#endif // !defined(__cpp_exceptions)

cores/esp8266/core_esp8266_postmortem.cpp

Lines changed: 61 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -36,41 +36,47 @@
3636

3737
extern "C" {
3838

39-
// These will be pointers to PROGMEM const strings
40-
static const char* s_panic_file = 0;
41-
static int s_panic_line = 0;
42-
static const char* s_panic_func = 0;
43-
static const char* s_panic_what = 0;
44-
45-
// Our wiring for abort() and C++ exceptions
46-
static bool s_abort_called = false;
47-
static const char* s_unhandled_exception = NULL;
48-
49-
// Common way to notify about where the stack smashing happened
50-
// (but, **only** if caller uses our handler function)
51-
static uint32_t s_stacksmash_addr = 0;
52-
53-
void abort() __attribute__((noreturn));
54-
static void uart_write_char_d(char c);
55-
static void uart0_write_char_d(char c);
56-
static void uart1_write_char_d(char c);
57-
static void print_stack(uint32_t start, uint32_t end);
58-
5939
// using numbers different from "REASON_" in user_interface.h (=0..6)
6040
enum rst_reason_sw
6141
{
6242
REASON_USER_STACK_SMASH = 253,
6343
REASON_USER_SWEXCEPTION_RST = 254
6444
};
65-
static int s_user_reset_reason = REASON_DEFAULT_RST;
45+
46+
static struct PostmortemInfo {
47+
int user_reset_reason; // REASON_DEFAULT_RST;
48+
49+
// These will be pointers to PROGMEM const strings
50+
const char* panic_file; // 0;
51+
int panic_line; // 0;
52+
const char* panic_func; // 0;
53+
const char* panic_what; // 0;
54+
55+
// Our wiring for abort() and C++ exceptions
56+
bool abort_called; // false;
57+
const char* unhandled_exception; // NULL;
58+
59+
// Common way to notify about where the stack smashing happened
60+
// (but, **only** if caller uses our handler function)
61+
uint32_t stacksmash_addr; // 0;
62+
} s_pm = {REASON_DEFAULT_RST, 0, 0, 0, 0, false, NULL, 0};
6663

6764
// From UMM, the last caller of a malloc/realloc/calloc which failed:
68-
extern void *umm_last_fail_alloc_addr;
69-
extern int umm_last_fail_alloc_size;
65+
extern struct umm_last_fail_alloc {
66+
const void *addr;
67+
size_t size;
7068
#if defined(DEBUG_ESP_OOM)
71-
extern const char *umm_last_fail_alloc_file;
72-
extern int umm_last_fail_alloc_line;
69+
const char *file;
70+
int line;
7371
#endif
72+
} _umm_last_fail_alloc;
73+
74+
75+
void abort() __attribute__((noreturn));
76+
static void uart_write_char_d(char c);
77+
static void uart0_write_char_d(char c);
78+
static void uart1_write_char_d(char c);
79+
static void print_stack(uint32_t start, uint32_t end);
7480

7581
static void raise_exception() __attribute__((noreturn));
7682

@@ -116,7 +122,7 @@ void __wrap_system_restart_local() {
116122

117123
struct rst_info rst_info;
118124
memset(&rst_info, 0, sizeof(rst_info));
119-
if (s_user_reset_reason == REASON_DEFAULT_RST)
125+
if (s_pm.user_reset_reason == REASON_DEFAULT_RST)
120126
{
121127
system_rtc_mem_read(0, &rst_info, sizeof(rst_info));
122128
if (rst_info.reason != REASON_SOFT_WDT_RST &&
@@ -127,23 +133,23 @@ void __wrap_system_restart_local() {
127133
}
128134
}
129135
else
130-
rst_info.reason = s_user_reset_reason;
136+
rst_info.reason = s_pm.user_reset_reason;
131137

132138
ets_install_putc1(&uart_write_char_d);
133139

134140
cut_here();
135141

136-
if (s_panic_line) {
137-
ets_printf_P(PSTR("\nPanic %S:%d %S"), s_panic_file, s_panic_line, s_panic_func);
138-
if (s_panic_what) {
139-
ets_printf_P(PSTR(": Assertion '%S' failed."), s_panic_what);
142+
if (s_pm.panic_line) {
143+
ets_printf_P(PSTR("\nPanic %S:%d %S"), s_pm.panic_file, s_pm.panic_line, s_pm.panic_func);
144+
if (s_pm.panic_what) {
145+
ets_printf_P(PSTR(": Assertion '%S' failed."), s_pm.panic_what);
140146
}
141147
ets_putc('\n');
142148
}
143-
else if (s_unhandled_exception) {
144-
ets_printf_P(PSTR("\nUnhandled C++ exception: %S\n"), s_unhandled_exception);
149+
else if (s_pm.unhandled_exception) {
150+
ets_printf_P(PSTR("\nUnhandled C++ exception: %S\n"), s_pm.unhandled_exception);
145151
}
146-
else if (s_abort_called) {
152+
else if (s_pm.abort_called) {
147153
ets_printf_P(PSTR("\nAbort called\n"));
148154
}
149155
else if (rst_info.reason == REASON_EXCEPTION_RST) {
@@ -159,8 +165,8 @@ void __wrap_system_restart_local() {
159165
else if (rst_info.reason == REASON_USER_STACK_SMASH) {
160166
ets_printf_P(PSTR("\nStack smashing detected.\n"));
161167
ets_printf_P(PSTR("\nException (%d):\nepc1=0x%08x epc2=0x%08x epc3=0x%08x excvaddr=0x%08x depc=0x%08x\n"),
162-
5 /* Alloca exception, closest thing to stack fault*/, s_stacksmash_addr, 0, 0, 0, 0);
163-
}
168+
5 /* Alloca exception, closest thing to stack fault*/, s_pm.stacksmash_addr, 0, 0, 0, 0);
169+
}
164170
else {
165171
ets_printf_P(PSTR("\nGeneric Reset\n"));
166172
}
@@ -211,22 +217,22 @@ void __wrap_system_restart_local() {
211217
ets_printf_P(PSTR("<<<stack<<<\n"));
212218

213219
// Use cap-X formatting to ensure the standard EspExceptionDecoder doesn't match the address
214-
if (umm_last_fail_alloc_addr) {
220+
if (_umm_last_fail_alloc.addr) {
215221
#if defined(DEBUG_ESP_OOM)
216222
ets_printf_P(PSTR("\nlast failed alloc call: %08X(%d)@%S:%d\n"),
217-
(uint32_t)umm_last_fail_alloc_addr, umm_last_fail_alloc_size,
218-
umm_last_fail_alloc_file, umm_last_fail_alloc_line);
223+
(uint32_t)_umm_last_fail_alloc.addr, _umm_last_fail_alloc.size,
224+
_umm_last_fail_alloc.file, _umm_last_fail_alloc.line);
219225
#else
220-
ets_printf_P(PSTR("\nlast failed alloc call: %08X(%d)\n"), (uint32_t)umm_last_fail_alloc_addr, umm_last_fail_alloc_size);
226+
ets_printf_P(PSTR("\nlast failed alloc call: %08X(%d)\n"), (uint32_t)_umm_last_fail_alloc.addr, _umm_last_fail_alloc.size);
221227
#endif
222228
}
223229

224230
cut_here();
225231

226-
if (s_unhandled_exception && umm_last_fail_alloc_addr) {
232+
if (s_pm.unhandled_exception && _umm_last_fail_alloc.addr) {
227233
// now outside from the "cut-here" zone, print correctly the `new` caller address,
228234
// idf-monitor.py will be able to decode this one and show exact location in sources
229-
ets_printf_P(PSTR("\nlast failed alloc caller: 0x%08x\n"), (uint32_t)umm_last_fail_alloc_addr);
235+
ets_printf_P(PSTR("\nlast failed alloc caller: 0x%08x\n"), (uint32_t)_umm_last_fail_alloc.addr);
230236
}
231237

232238
custom_crash_callback( &rst_info, sp_dump + offset, stack_end );
@@ -275,45 +281,45 @@ static void raise_exception() {
275281
if (gdb_present())
276282
__asm__ __volatile__ ("syscall"); // triggers GDB when enabled
277283

278-
s_user_reset_reason = REASON_USER_SWEXCEPTION_RST;
284+
s_pm.user_reset_reason = REASON_USER_SWEXCEPTION_RST;
279285
ets_printf_P(PSTR("\nUser exception (panic/abort/assert)"));
280286
__wrap_system_restart_local();
281287

282288
while (1); // never reached, needed to satisfy "noreturn" attribute
283289
}
284290

285291
void abort() {
286-
s_abort_called = true;
292+
s_pm.abort_called = true;
287293
raise_exception();
288294
}
289295

290296
void __unhandled_exception(const char *str) {
291-
s_unhandled_exception = str;
297+
s_pm.unhandled_exception = str;
292298
raise_exception();
293299
}
294300

295301
void __assert_func(const char *file, int line, const char *func, const char *what) {
296-
s_panic_file = file;
297-
s_panic_line = line;
298-
s_panic_func = func;
299-
s_panic_what = what;
302+
s_pm.panic_file = file;
303+
s_pm.panic_line = line;
304+
s_pm.panic_func = func;
305+
s_pm.panic_what = what;
300306
gdb_do_break(); /* if GDB is not present, this is a no-op */
301307
raise_exception();
302308
}
303309

304310
void __panic_func(const char* file, int line, const char* func) {
305-
s_panic_file = file;
306-
s_panic_line = line;
307-
s_panic_func = func;
308-
s_panic_what = 0;
311+
s_pm.panic_file = file;
312+
s_pm.panic_line = line;
313+
s_pm.panic_func = func;
314+
s_pm.panic_what = 0;
309315
gdb_do_break(); /* if GDB is not present, this is a no-op */
310316
raise_exception();
311317
}
312318

313319
uintptr_t __stack_chk_guard = 0x08675309 ^ RANDOM_REG32;
314320
void __stack_chk_fail(void) {
315-
s_user_reset_reason = REASON_USER_STACK_SMASH;
316-
s_stacksmash_addr = (uint32_t)__builtin_return_address(0);
321+
s_pm.user_reset_reason = REASON_USER_STACK_SMASH;
322+
s_pm.stacksmash_addr = (uint32_t)__builtin_return_address(0);
317323

318324
if (gdb_present())
319325
__asm__ __volatile__ ("syscall"); // triggers GDB when enabled

0 commit comments

Comments
 (0)