Avoid crashes during fault handler

If the fault handler was hit before the stdio console was used and
initialised, the initialisation code caused a "mutex in ISR" trap,
stopping the register dump from happening.

Temporarily set the `error_in_progress` flag at the top of the fault
handler, and restore it before calling `mbed_error`. Take the
opportunity to suppress fault dumps on recursive crashes, much as is
done inside `mbed_error`.
pull/11970/head
Kevin Bracey 2019-11-28 12:44:11 +02:00
parent b0751bf507
commit fc05d51bcd
3 changed files with 38 additions and 29 deletions

View File

@ -168,7 +168,7 @@ void mbed_error_vprintf(const char *format, va_list arg) MBED_PRINTF(1, 0);
* FileHandle::write of the stderr device is. The default * FileHandle::write of the stderr device is. The default
* serial console is safe, either buffered or not. If the * serial console is safe, either buffered or not. If the
* console has not previously been initialized, an attempt * console has not previously been initialized, an attempt
* to use this from interrupt may during console initialization. * to use this from interrupt may crash during console initialization.
* Special handling of `mbed_error` relaxes various system traps * Special handling of `mbed_error` relaxes various system traps
* to increase the chance of initialization working. * to increase the chance of initialization working.
* *

View File

@ -21,6 +21,7 @@
#include <string.h> #include <string.h>
#include "device.h" #include "device.h"
#include "mbed_atomic.h"
#include "mbed_error.h" #include "mbed_error.h"
#include "mbed_interface.h" #include "mbed_interface.h"
#include "mbed_crash_data_offsets.h" #include "mbed_crash_data_offsets.h"
@ -39,41 +40,49 @@ mbed_fault_context_t fault_context;
mbed_fault_context_t *const mbed_fault_context = &fault_context; mbed_fault_context_t *const mbed_fault_context = &fault_context;
#endif #endif
extern bool mbed_error_in_progress;
//This is a handler function called from Fault handler to print the error information out. //This is a handler function called from Fault handler to print the error information out.
//This runs in fault context and uses special functions(defined in mbed_rtx_fault_handler.c) to print the information without using C-lib support. //This runs in fault context and uses special functions(defined in mbed_rtx_fault_handler.c) to print the information without using C-lib support.
void mbed_fault_handler(uint32_t fault_type, const mbed_fault_context_t *mbed_fault_context_in) void mbed_fault_handler(uint32_t fault_type, const mbed_fault_context_t *mbed_fault_context_in)
{ {
mbed_error_status_t faultStatus = MBED_SUCCESS; mbed_error_status_t faultStatus = MBED_SUCCESS;
mbed_error_printf("\n++ MbedOS Fault Handler ++\n\nFaultType: "); /* Need to set the flag to ensure prints do not trigger a "mutex in ISR" trap
* if they're first prints since boot and we have to init the I/O system.
*/
if (!core_util_atomic_exchange_bool(&mbed_error_in_progress, true)) {
mbed_error_printf("\n++ MbedOS Fault Handler ++\n\nFaultType: ");
switch (fault_type) { switch (fault_type) {
case MEMMANAGE_FAULT_EXCEPTION: case MEMMANAGE_FAULT_EXCEPTION:
mbed_error_printf("MemManageFault"); mbed_error_printf("MemManageFault");
faultStatus = MBED_ERROR_MEMMANAGE_EXCEPTION; faultStatus = MBED_ERROR_MEMMANAGE_EXCEPTION;
break; break;
case BUS_FAULT_EXCEPTION: case BUS_FAULT_EXCEPTION:
mbed_error_printf("BusFault"); mbed_error_printf("BusFault");
faultStatus = MBED_ERROR_BUSFAULT_EXCEPTION; faultStatus = MBED_ERROR_BUSFAULT_EXCEPTION;
break; break;
case USAGE_FAULT_EXCEPTION: case USAGE_FAULT_EXCEPTION:
mbed_error_printf("UsageFault"); mbed_error_printf("UsageFault");
faultStatus = MBED_ERROR_USAGEFAULT_EXCEPTION; faultStatus = MBED_ERROR_USAGEFAULT_EXCEPTION;
break; break;
//There is no way we can hit this code without getting an exception, so we have the default treated like hardfault //There is no way we can hit this code without getting an exception, so we have the default treated like hardfault
case HARD_FAULT_EXCEPTION: case HARD_FAULT_EXCEPTION:
default: default:
mbed_error_printf("HardFault"); mbed_error_printf("HardFault");
faultStatus = MBED_ERROR_HARDFAULT_EXCEPTION; faultStatus = MBED_ERROR_HARDFAULT_EXCEPTION;
break; break;
}
mbed_error_printf("\n\nContext:");
print_context_info();
mbed_error_printf("\n\n-- MbedOS Fault Handler --\n\n");
core_util_atomic_store_bool(&mbed_error_in_progress, false);
} }
mbed_error_printf("\n\nContext:");
print_context_info();
mbed_error_printf("\n\n-- MbedOS Fault Handler --\n\n");
//Now call mbed_error, to log the error and halt the system //Now call mbed_error, to log the error and halt the system
mbed_error(faultStatus, "Fault exception", (unsigned int)mbed_fault_context_in, NULL, 0); mbed_error(faultStatus, "Fault exception", (unsigned int)mbed_fault_context_in, NULL, 0);

View File

@ -51,7 +51,7 @@ static void print_error_report(const mbed_error_ctx *ctx, const char *, const ch
#define ERROR_REPORT(ctx, error_msg, error_filename, error_line) ((void) 0) #define ERROR_REPORT(ctx, error_msg, error_filename, error_line) ((void) 0)
#endif #endif
static bool error_in_progress; bool mbed_error_in_progress;
static core_util_atomic_flag halt_in_progress = CORE_UTIL_ATOMIC_FLAG_INIT; static core_util_atomic_flag halt_in_progress = CORE_UTIL_ATOMIC_FLAG_INIT;
static int error_count = 0; static int error_count = 0;
static mbed_error_ctx first_error_ctx = {0}; static mbed_error_ctx first_error_ctx = {0};
@ -121,7 +121,7 @@ static MBED_NORETURN void mbed_halt_system(void)
WEAK MBED_NORETURN void error(const char *format, ...) WEAK MBED_NORETURN void error(const char *format, ...)
{ {
// Prevent recursion if error is called again during store+print attempt // Prevent recursion if error is called again during store+print attempt
if (!core_util_atomic_exchange_bool(&error_in_progress, true)) { if (!core_util_atomic_exchange_bool(&mbed_error_in_progress, true)) {
handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0, MBED_CALLER_ADDR()); handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0, MBED_CALLER_ADDR());
ERROR_REPORT(&last_error_ctx, "Fatal Run-time error", NULL, 0); ERROR_REPORT(&last_error_ctx, "Fatal Run-time error", NULL, 0);
@ -298,7 +298,7 @@ int mbed_get_error_count(void)
//Reads the fatal error occurred" flag //Reads the fatal error occurred" flag
bool mbed_get_error_in_progress(void) bool mbed_get_error_in_progress(void)
{ {
return core_util_atomic_load_bool(&error_in_progress); return core_util_atomic_load_bool(&mbed_error_in_progress);
} }
//Sets a non-fatal error //Sets a non-fatal error
@ -311,7 +311,7 @@ mbed_error_status_t mbed_warning(mbed_error_status_t error_status, const char *e
WEAK MBED_NORETURN mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number) WEAK MBED_NORETURN mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number)
{ {
// Prevent recursion if error is called again during store+print attempt // Prevent recursion if error is called again during store+print attempt
if (!core_util_atomic_exchange_bool(&error_in_progress, true)) { if (!core_util_atomic_exchange_bool(&mbed_error_in_progress, true)) {
//set the error reported //set the error reported
(void) handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR()); (void) handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR());