Fatal exceptions: Cleanly deal with exceptions that occur inside fatal_exception_handler_inner()
In case of heap corruption or some other major problem, dumping details in the exception handler can cause a crash loop - so fail out if we seem to be going in circles.
This commit is contained in:
parent
981c87899b
commit
1e9296f60c
2 changed files with 33 additions and 18 deletions
|
@ -24,10 +24,14 @@
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
static void IRAM fatal_handler_prelude(void);
|
static void IRAM fatal_handler_prelude(void);
|
||||||
/* Inner parts of crash handlers marked noinline to ensure they don't inline into IRAM. */
|
/* Inner parts of crash handlers */
|
||||||
static void __attribute__((noinline)) __attribute__((noreturn)) fatal_exception_handler_inner(uint32_t *sp, bool registers_saved_on_stack);
|
typedef void __attribute__((noreturn)) (*fatal_exception_handler_fn)(uint32_t *sp, bool registers_saved_on_stack);
|
||||||
|
static void __attribute__((noreturn)) standard_fatal_exception_handler_inner(uint32_t *sp, bool registers_saved_on_stack);
|
||||||
|
static void __attribute__((noreturn)) second_fatal_exception_handler_inner(uint32_t *sp, bool registers_saved_on_stack);
|
||||||
static void __attribute__((noinline)) __attribute__((noreturn)) abort_handler_inner(uint32_t *caller, uint32_t *sp);
|
static void __attribute__((noinline)) __attribute__((noreturn)) abort_handler_inner(uint32_t *caller, uint32_t *sp);
|
||||||
|
|
||||||
|
static IRAM_DATA fatal_exception_handler_fn fatal_exception_handler_inner = standard_fatal_exception_handler_inner;
|
||||||
|
|
||||||
/* fatal_exception_handler called from any unhandled user exception
|
/* fatal_exception_handler called from any unhandled user exception
|
||||||
*
|
*
|
||||||
* (similar to a hard fault on other processor architectures)
|
* (similar to a hard fault on other processor architectures)
|
||||||
|
@ -38,7 +42,8 @@ static void __attribute__((noinline)) __attribute__((noreturn)) abort_handler_in
|
||||||
*/
|
*/
|
||||||
void IRAM __attribute__((noreturn)) fatal_exception_handler(uint32_t *sp, bool registers_saved_on_stack) {
|
void IRAM __attribute__((noreturn)) fatal_exception_handler(uint32_t *sp, bool registers_saved_on_stack) {
|
||||||
fatal_handler_prelude();
|
fatal_handler_prelude();
|
||||||
fatal_exception_handler_inner(sp, registers_saved_on_stack);
|
fatal_exception_handler_fn inner_fn = fatal_exception_handler_inner;
|
||||||
|
inner_fn(sp, registers_saved_on_stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Abort implementation
|
/* Abort implementation
|
||||||
|
@ -132,6 +137,12 @@ void dump_registers_in_exception_handler(uint32_t *sp) {
|
||||||
printf("SAR %08x\n", saved[0x13]);
|
printf("SAR %08x\n", saved[0x13]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __attribute__((noreturn)) post_crash_reset(void) {
|
||||||
|
uart_flush_txfifo(0);
|
||||||
|
uart_flush_txfifo(1);
|
||||||
|
sdk_system_restart_in_nmi();
|
||||||
|
while(1) {}
|
||||||
|
}
|
||||||
|
|
||||||
/* Prelude ensures exceptions/NMI off and flash is mapped, allowing
|
/* Prelude ensures exceptions/NMI off and flash is mapped, allowing
|
||||||
calls to non-IRAM functions.
|
calls to non-IRAM functions.
|
||||||
|
@ -150,7 +161,10 @@ static void IRAM fatal_handler_prelude(void) {
|
||||||
/* Main part of fatal exception handler, is run from flash to save
|
/* Main part of fatal exception handler, is run from flash to save
|
||||||
some IRAM.
|
some IRAM.
|
||||||
*/
|
*/
|
||||||
static void fatal_exception_handler_inner(uint32_t *sp, bool registers_saved_on_stack) {
|
static void standard_fatal_exception_handler_inner(uint32_t *sp, bool registers_saved_on_stack) {
|
||||||
|
/* Replace the fatal exception handler 'inner' function so we
|
||||||
|
don't end up in a crash loop if this handler crashes. */
|
||||||
|
fatal_exception_handler_inner = second_fatal_exception_handler_inner;
|
||||||
dump_excinfo();
|
dump_excinfo();
|
||||||
if (sp) {
|
if (sp) {
|
||||||
if (registers_saved_on_stack) {
|
if (registers_saved_on_stack) {
|
||||||
|
@ -159,10 +173,16 @@ static void fatal_exception_handler_inner(uint32_t *sp, bool registers_saved_on_
|
||||||
dump_stack(sp);
|
dump_stack(sp);
|
||||||
}
|
}
|
||||||
dump_heapinfo();
|
dump_heapinfo();
|
||||||
uart_flush_txfifo(0);
|
post_crash_reset();
|
||||||
uart_flush_txfifo(1);
|
}
|
||||||
sdk_system_restart_in_nmi();
|
|
||||||
while(1) {}
|
/* This is the exception handler that gets called if a crash occurs inside the standard handler,
|
||||||
|
so we don't end up in a crash loop. It doesn't rely on contents of stack or heap.
|
||||||
|
*/
|
||||||
|
static void second_fatal_exception_handler_inner(uint32_t *sp, bool registers_saved_on_stack) {
|
||||||
|
dump_excinfo();
|
||||||
|
printf("Second fatal exception occured inside fatal exception handler. Can't continue.\n");
|
||||||
|
post_crash_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump_heapinfo(void)
|
void dump_heapinfo(void)
|
||||||
|
@ -207,8 +227,5 @@ static void abort_handler_inner(uint32_t *caller, uint32_t *sp) {
|
||||||
printf("abort() invoked at %p.\n", caller);
|
printf("abort() invoked at %p.\n", caller);
|
||||||
dump_stack(sp);
|
dump_stack(sp);
|
||||||
dump_heapinfo();
|
dump_heapinfo();
|
||||||
uart_flush_txfifo(0);
|
post_crash_reset();
|
||||||
uart_flush_txfifo(1);
|
|
||||||
sdk_system_restart_in_nmi();
|
|
||||||
while(1) {}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,18 +65,16 @@
|
||||||
*/
|
*/
|
||||||
#define IRAM __attribute__((section(".iram1.text")))
|
#define IRAM __attribute__((section(".iram1.text")))
|
||||||
|
|
||||||
/* Use this macro to place read-only data into Instruction RAM (IRAM)
|
/* Use this macro to place data into Instruction RAM (IRAM)
|
||||||
instead of loaded into rodata which resides in DRAM.
|
instead of loaded into rodata which resides in DRAM.
|
||||||
|
|
||||||
|
(IRAM can also be written to as necessary.)
|
||||||
|
|
||||||
This may be useful to free up data RAM. However all data read from
|
This may be useful to free up data RAM. However all data read from
|
||||||
the instruction space must be 32-bit aligned word reads
|
the instruction space must be 32-bit aligned word reads
|
||||||
(non-aligned reads will use an interrupt routine to "fix" them and
|
(non-aligned reads will use an interrupt routine to "fix" them and
|
||||||
still work, but are very slow..
|
still work, but are very slow..
|
||||||
*/
|
*/
|
||||||
#ifdef __cplusplus
|
#define IRAM_DATA __attribute__((section(".iram1.rodata")))
|
||||||
#define IRAM_DATA __attribute__((section(".iram1.rodata")))
|
|
||||||
#else
|
|
||||||
#define IRAM_DATA __attribute__((section(".iram1.rodata"))) const
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue