mirror of https://github.com/ARMmbed/mbed-os.git
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
parent
b0751bf507
commit
fc05d51bcd
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue