Skip to content

Commit

Permalink
Avoid crashes during fault handler
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
kjbracey committed Nov 28, 2019
1 parent b0751bf commit 0130151
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 33 deletions.
2 changes: 1 addition & 1 deletion platform/mbed_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
* serial console is safe, either buffered or not. If the
* 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
* to increase the chance of initialization working.
*
Expand Down
64 changes: 36 additions & 28 deletions platform/source/TARGET_CORTEX_M/mbed_fault_handler.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,41 +39,49 @@ mbed_fault_context_t fault_context;
mbed_fault_context_t *const mbed_fault_context = &fault_context;
#endif

extern bool mbed_error_in_progress;

//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.
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_printf("\n++ MbedOS Fault Handler ++\n\nFaultType: ");

switch (fault_type) {
case MEMMANAGE_FAULT_EXCEPTION:
mbed_error_printf("MemManageFault");
faultStatus = MBED_ERROR_MEMMANAGE_EXCEPTION;
break;

case BUS_FAULT_EXCEPTION:
mbed_error_printf("BusFault");
faultStatus = MBED_ERROR_BUSFAULT_EXCEPTION;
break;

case USAGE_FAULT_EXCEPTION:
mbed_error_printf("UsageFault");
faultStatus = MBED_ERROR_USAGEFAULT_EXCEPTION;
break;

//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:
default:
mbed_error_printf("HardFault");
faultStatus = MBED_ERROR_HARDFAULT_EXCEPTION;
break;
}
mbed_error_printf("\n\nContext:");
print_context_info();
/* 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) {
case MEMMANAGE_FAULT_EXCEPTION:
mbed_error_printf("MemManageFault");
faultStatus = MBED_ERROR_MEMMANAGE_EXCEPTION;
break;

case BUS_FAULT_EXCEPTION:
mbed_error_printf("BusFault");
faultStatus = MBED_ERROR_BUSFAULT_EXCEPTION;
break;

case USAGE_FAULT_EXCEPTION:
mbed_error_printf("UsageFault");
faultStatus = MBED_ERROR_USAGEFAULT_EXCEPTION;
break;

//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:
default:
mbed_error_printf("HardFault");
faultStatus = MBED_ERROR_HARDFAULT_EXCEPTION;
break;
}
mbed_error_printf("\n\nContext:");
print_context_info();

mbed_error_printf("\n\n-- MbedOS Fault Handler --\n\n");
mbed_error_printf("\n\n-- MbedOS Fault Handler --\n\n");
core_util_atomic_store_bool(&mbed_error_in_progress, false);
}

//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);
Expand Down
8 changes: 4 additions & 4 deletions platform/source/mbed_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
#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 int error_count = 0;
static mbed_error_ctx first_error_ctx = {0};
Expand Down Expand Up @@ -121,7 +121,7 @@ static MBED_NORETURN void mbed_halt_system(void)
WEAK MBED_NORETURN void error(const char *format, ...)
{
// 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());
ERROR_REPORT(&last_error_ctx, "Fatal Run-time error", NULL, 0);

Expand Down Expand Up @@ -298,7 +298,7 @@ int mbed_get_error_count(void)
//Reads the fatal error occurred" flag
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
Expand All @@ -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)
{
// 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
(void) handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR());

Expand Down

0 comments on commit 0130151

Please sign in to comment.