Merge pull request #7214 from SenRamakri/sen_ErrorOptimAndConfig

Error handling configuration updates and Optimization for exception handling
pull/7113/merge
Cruz Monrreal 2018-06-25 10:10:49 -05:00 committed by GitHub
commit ea47342f81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 257 additions and 364 deletions

View File

@ -132,12 +132,12 @@ void test_error_context_capture()
TEST_ASSERT_EQUAL_UINT((uint32_t)current_thread->thread_addr, error_ctx.thread_entry_address);
TEST_ASSERT_EQUAL_UINT((uint32_t)current_thread->stack_size, error_ctx.thread_stack_size);
TEST_ASSERT_EQUAL_UINT((uint32_t)current_thread->stack_mem, error_ctx.thread_stack_mem);
#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED
#if MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED
TEST_ASSERT_EQUAL_STRING(MBED_FILENAME, error_ctx.error_filename);
#endif
}
#ifndef MBED_CONF_ERROR_HIST_DISABLED
#if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
/** Test error logging functionality
*/
void test_error_logging()
@ -261,7 +261,7 @@ void test_error_hook()
TEST_ASSERT(sem_status > 0);
}
#ifdef MBED_TEST_SIM_BLOCKDEVICE
#if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED && defined(MBED_TEST_SIM_BLOCKDEVICE)
// test configuration
#ifndef MBED_TEST_FILESYSTEM
@ -351,12 +351,12 @@ Case cases[] = {
Case("Test error context capture", test_error_context_capture),
#endif //MBED_CONF_RTOS_PRESENT
Case("Test error hook", test_error_hook),
#ifndef MBED_CONF_ERROR_HIST_DISABLED
#if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
Case("Test error logging", test_error_logging),
#if MBED_CONF_RTOS_PRESENT
Case("Test error handling multi-threaded", test_error_logging_multithread),
#endif //MBED_CONF_RTOS_PRESENT
#ifdef MBED_TEST_SIM_BLOCKDEVICE
#if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED && defined(MBED_TEST_SIM_BLOCKDEVICE)
Case("Test error save log", test_save_error_log),
#endif //MBED_TEST_SIM_BLOCKDEVICE
#endif //MBED_CONF_ERROR_HIST_DISABLED

View File

@ -33,7 +33,7 @@
#define GET_CURRENT_SP(sp) \
{ \
/*If in Handler mode we are always using MSP*/ \
if( __get_IPSR() != 0U ) { \
if ( __get_IPSR() != 0U ) { \
sp = __get_MSP(); \
} else { \
/*Look into CONTROL.SPSEL value*/ \
@ -95,7 +95,7 @@ static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsign
mbed_error_ctx current_error_ctx;
//Error status should always be < 0
if(error_status >= 0) {
if (error_status >= 0) {
//This is a weird situation, someone called mbed_error with invalid error code.
//We will still handle the situation but change the error code to ERROR_INVALID_ARGUMENT, atleast the context will have info on who called it
error_status = MBED_ERROR_INVALID_ARGUMENT;
@ -132,29 +132,29 @@ static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsign
#endif //MBED_CONF_RTOS_PRESENT
#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED
#ifdef MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED
//Capture filename/linenumber if provided
//Index for tracking error_filename
memset(&current_error_ctx.error_filename, 0, MBED_CONF_MAX_ERROR_FILENAME_LEN);
strncpy(current_error_ctx.error_filename, filename, MBED_CONF_MAX_ERROR_FILENAME_LEN);
memset(&current_error_ctx.error_filename, 0, MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN);
strncpy(current_error_ctx.error_filename, filename, MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN);
current_error_ctx.error_line_number = line_number;
#endif
//Capture the fist system error and store it
if(error_count == 1) { //first error
if (error_count == 1) { //first error
memcpy(&first_error_ctx, &current_error_ctx, sizeof(mbed_error_ctx));
}
//copy this error to last error
memcpy(&last_error_ctx, &current_error_ctx, sizeof(mbed_error_ctx));
#ifndef MBED_CONF_ERROR_HIST_DISABLED
#if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
//Log the error with error log
mbed_error_hist_put(&current_error_ctx);
#endif
//Call the error hook if available
if(error_hook != NULL) {
if (error_hook != NULL) {
error_hook(&last_error_ctx);
}
@ -190,11 +190,11 @@ mbed_error_status_t mbed_warning(mbed_error_status_t error_status, const char *e
return handle_error(error_status, error_value, filename, line_number);
}
//Sets a fatal error
//Sets a fatal error, this function is marked WEAK to be able to override this for some tests
WEAK 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)
{
//set the error reported and then halt the system
if( MBED_SUCCESS != handle_error(error_status, error_value, filename, line_number) )
if ( MBED_SUCCESS != handle_error(error_status, error_value, filename, line_number))
return MBED_ERROR_FAILED_OPERATION;
//On fatal errors print the error context/report
@ -208,7 +208,7 @@ WEAK mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char
mbed_error_status_t mbed_set_error_hook(mbed_error_hook_t error_hook_in)
{
//register the new hook/callback
if( error_hook_in != NULL ) {
if ( error_hook_in != NULL ) {
error_hook = error_hook_in;
return MBED_SUCCESS;
}
@ -236,17 +236,17 @@ mbed_error_status_t mbed_make_error(mbed_error_type_t error_type, mbed_module_ty
switch(error_type)
{
case MBED_ERROR_TYPE_POSIX:
if(error_code >= MBED_POSIX_ERROR_BASE && error_code <= MBED_SYSTEM_ERROR_BASE)
if (error_code >= MBED_POSIX_ERROR_BASE && error_code <= MBED_SYSTEM_ERROR_BASE)
return -error_code;
break;
case MBED_ERROR_TYPE_SYSTEM:
if(error_code >= MBED_SYSTEM_ERROR_BASE && error_code <= MBED_CUSTOM_ERROR_BASE)
if (error_code >= MBED_SYSTEM_ERROR_BASE && error_code <= MBED_CUSTOM_ERROR_BASE)
return MAKE_MBED_ERROR(MBED_ERROR_TYPE_SYSTEM, entity, error_code);
break;
case MBED_ERROR_TYPE_CUSTOM:
if(error_code >= MBED_CUSTOM_ERROR_BASE)
if (error_code >= MBED_CUSTOM_ERROR_BASE)
return MAKE_MBED_ERROR(MBED_ERROR_TYPE_CUSTOM, entity, error_code);
break;
@ -273,7 +273,7 @@ mbed_error_status_t mbed_clear_all_errors(void)
memset(&last_error_ctx, sizeof(mbed_error_ctx), 0);
//reset error count to 0
error_count = 0;
#ifndef MBED_CONF_ERROR_HIST_DISABLED
#if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
status = mbed_error_hist_reset();
#endif
core_util_critical_section_exit();
@ -281,7 +281,109 @@ mbed_error_status_t mbed_clear_all_errors(void)
return status;
}
#ifndef MBED_CONF_ERROR_HIST_DISABLED
#if MBED_CONF_PLATFORM_ERROR_ALL_THREADS_INFO && defined(MBED_CONF_RTOS_PRESENT)
/* Prints info of a thread(using osRtxThread_t struct)*/
static void print_thread(osRtxThread_t *thread)
{
mbed_error_printf("\nState: 0x%08X Entry: 0x%08X Stack Size: 0x%08X Mem: 0x%08X SP: 0x%08X", thread->state, thread->thread_addr, thread->stack_size, (uint32_t)thread->stack_mem, thread->sp);
}
/* Prints thread info from a list */
static void print_threads_info(osRtxThread_t *threads)
{
while (threads != NULL) {
print_thread( threads );
threads = threads->thread_next;
}
}
#endif
static void print_error_report(mbed_error_ctx *ctx, const char *error_msg)
{
uint32_t error_code = MBED_GET_ERROR_CODE(ctx->error_status);
uint32_t error_module = MBED_GET_ERROR_MODULE(ctx->error_status);
mbed_error_printf("\n\n++ MbedOS Error Info ++\nError Status: 0x%X Code: %d Module: %d\nError Message: ", ctx->error_status, error_code, error_module);
switch (error_code) {
//These are errors reported by kernel handled from mbed_rtx_handlers
case MBED_ERROR_CODE_RTOS_EVENT:
mbed_error_printf("Kernel Error: 0x%X, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_THREAD_EVENT:
mbed_error_printf("Thread: 0x%X, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_MUTEX_EVENT:
mbed_error_printf("Mutex: 0x%X, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT:
mbed_error_printf("Semaphore: 0x%X, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT:
mbed_error_printf("MemoryPool: 0x%X, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT:
mbed_error_printf("EventFlags: 0x%X, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_TIMER_EVENT:
mbed_error_printf("Timer: 0x%X, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT:
mbed_error_printf("MessageQueue: 0x%X, ", ctx->error_value);
break;
default:
//Nothing to do here, just print the error info down
break;
}
mbed_error_printf(error_msg);
mbed_error_printf("\nLocation: 0x%X", ctx->error_address);
#if MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED && !defined(NDEBUG)
if ((NULL != ctx->error_filename[0]) && (ctx->error_line_number != 0)) {
//for string, we must pass address of a ptr which has the address of the string
mbed_error_printf("\nFile:%s+%d", ctx->error_filename, ctx->error_line_number);
}
#endif
mbed_error_printf("\nError Value: 0x%X", ctx->error_value);
#ifdef TARGET_CORTEX_M
mbed_error_printf("\nCurrent Thread: Id: 0x%X Entry: 0x%X StackSize: 0x%X StackMem: 0x%X SP: 0x%X ",
ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem, ctx->thread_current_sp);
#else
//For Cortex-A targets we dont have support to capture the current SP
mbed_error_printf("\nCurrent Thread: Id: 0x%X Entry: 0x%X StackSize: 0x%X StackMem: 0x%X ",
ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem);
#endif //TARGET_CORTEX_M
#if MBED_CONF_PLATFORM_ERROR_ALL_THREADS_INFO && defined(MBED_CONF_RTOS_PRESENT)
mbed_error_printf("\nNext:");
print_thread(osRtxInfo.thread.run.next);
mbed_error_printf("\nWait:");
osRtxThread_t *threads = (osRtxThread_t *)&osRtxInfo.thread.wait_list;
print_threads_info(threads);
mbed_error_printf("\nDelay:");
threads = (osRtxThread_t *)&osRtxInfo.thread.delay_list;
print_threads_info(threads);
mbed_error_printf("\nIdle:");
threads = (osRtxThread_t *)&osRtxInfo.thread.idle;
print_threads_info(threads);
#endif
mbed_error_printf("\n-- MbedOS Error Info --\n");
}
#if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
//Retrieve the error context from error log at the specified index
mbed_error_status_t mbed_get_error_hist_info (int index, mbed_error_ctx *error_info)
{
@ -302,19 +404,19 @@ mbed_error_status_t mbed_save_error_hist(const char *path)
FILE *error_log_file = NULL;
//Ensure path is valid
if(path==NULL) {
if (path==NULL) {
ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INVALID_ARGUMENT);
goto exit;
}
//Open the file for saving the error log info
if((error_log_file = fopen( path, "w" ) ) == NULL){
if ((error_log_file = fopen( path, "w" )) == NULL){
ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OPEN_FAILED);
goto exit;
}
//First store the first and last errors
if(fprintf(error_log_file, "\nFirst Error: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n",
if (fprintf(error_log_file, "\nFirst Error: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n",
(unsigned int)first_error_ctx.error_status,
(unsigned int)first_error_ctx.thread_id,
(unsigned int)first_error_ctx.error_address,
@ -323,7 +425,7 @@ mbed_error_status_t mbed_save_error_hist(const char *path)
goto exit;
}
if(fprintf(error_log_file, "\nLast Error: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n",
if (fprintf(error_log_file, "\nLast Error: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n",
(unsigned int)last_error_ctx.error_status,
(unsigned int)last_error_ctx.thread_id,
(unsigned int)last_error_ctx.error_address,
@ -333,10 +435,10 @@ mbed_error_status_t mbed_save_error_hist(const char *path)
}
//Update with error log info
while(--log_count >= 0) {
while (--log_count >= 0) {
mbed_error_hist_get(log_count, &ctx);
//first line of file will be error log count
if(fprintf(error_log_file, "\n%d: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n",
if (fprintf(error_log_file, "\n%d: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n",
log_count,
(unsigned int)ctx.error_status,
(unsigned int)ctx.thread_id,
@ -352,83 +454,5 @@ exit:
return ret;
}
static void print_error_report(mbed_error_ctx *ctx, const char *error_msg)
{
uint32_t error_code = MBED_GET_ERROR_CODE(ctx->error_status);
uint32_t error_module = MBED_GET_ERROR_MODULE(ctx->error_status);
mbed_error_printf("\n\n++ MbedOS Error Info ++\nError Status: 0x%x Code: %d Module: %d\nError Message: ", ctx->error_status, error_code, error_module);
//Report error info based on error code, some errors require different
//error_vals[1] contains the error code
if(error_code == MBED_ERROR_CODE_HARDFAULT_EXCEPTION ||
error_code == MBED_ERROR_CODE_MEMMANAGE_EXCEPTION ||
error_code == MBED_ERROR_CODE_BUSFAULT_EXCEPTION ||
error_code == MBED_ERROR_CODE_USAGEFAULT_EXCEPTION ) {
mbed_error_printf(error_msg);
mbed_error_printf("\nLocation: 0x%x\n", ctx->error_value);
} else {
switch (error_code) {
//These are errors reported by kernel handled from mbed_rtx_handlers
case MBED_ERROR_CODE_RTOS_EVENT:
mbed_error_printf("Kernel Error: 0x%x, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_THREAD_EVENT:
mbed_error_printf("Thread: 0x%x, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_MUTEX_EVENT:
mbed_error_printf("Mutex: 0x%x, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT:
mbed_error_printf("Semaphore: 0x%x, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT:
mbed_error_printf("MemoryPool: 0x%x, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT:
mbed_error_printf("EventFlags: 0x%x, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_TIMER_EVENT:
mbed_error_printf("Timer: 0x%x, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT:
mbed_error_printf("MessageQueue: 0x%x, ", ctx->error_value);
break;
default:
//Nothing to do here, just print the error info down
break;
}
mbed_error_printf(error_msg, NULL);
mbed_error_printf("\nLocation: 0x%x", ctx->error_address);
#if defined(MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED) && !defined(NDEBUG)
if(NULL != ctx->error_filename) {
//for string, we must pass address of a ptr which has the address of the string
mbed_error_printf("\nFile:%s+%d", ctx->error_filename, ctx->error_line_number);
}
#endif
#ifdef TARGET_CORTEX_M
mbed_error_printf("\nError Value: 0x%x\nCurrent Thread: Id: 0x%x Entry: 0x%x StackSize: 0x%x StackMem: 0x%x SP: 0x%x ",
ctx->error_value, ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem, ctx->thread_current_sp);
#else
//For Cortex-A targets we dont have support to capture the current SP
mbed_error_printf("\nError Value: 0x%x\nCurrent Thread: Id: 0x%x Entry: 0x%x StackSize: 0x%x StackMem: 0x%x ",
ctx->error_value, ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem);
#endif //TARGET_CORTEX_M
}
mbed_error_printf("\n-- MbedOS Error Info --\n");
}
#endif

View File

@ -30,15 +30,22 @@ extern "C" {
#endif
/** Define this macro to include filenames in error context. For release builds, do not include filename to save memory.
* MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED
* MBED_PLATFORM_CONF_ERROR_FILENAME_CAPTURE_ENABLED
*/
/** Define this macro to disable error logging, note that the first and last error capture will still be active by default.
* MBED_CONF_ERROR_HIST_DISABLED
* MBED_PLATFORM_CONF_ERROR_HIST_DISABLED
*/
#ifndef MBED_CONF_MAX_ERROR_FILENAME_LEN
#define MBED_CONF_MAX_ERROR_FILENAME_LEN 16
#ifndef MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN
#define MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN 16
#else //MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN
#if MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN > 64
//We have to limit this to 64 bytes since we use mbed_error_printf for error reporting
//and mbed_error_vfprintf uses 128bytes internal buffer which may not be sufficient for anything
//longer that 64 bytes with the current implementation.
#error "Unsupported error filename buffer length detected, max supported length is 64 chars. Please change MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN or max-error-filename-len in configuration."
#endif
#endif
#define MBED_ERROR_STATUS_CODE_MASK (0x0000FFFF)
@ -144,16 +151,16 @@ typedef int mbed_error_status_t;
*
*/
#ifdef NDEBUG
#define MBED_WARNING1( error_status, error_msg, error_value ) mbed_warning( error_status, (const char *)NULL, (uint32_t)error_value, NULL, 0 )
#define MBED_WARNING( error_status, error_msg ) mbed_warning( error_status, (const char *)NULL, (uint32_t)0, NULL, 0 )
#else
#if defined(MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED)
#define MBED_WARNING1( error_status, error_msg, error_value ) mbed_warning( error_status, (const char *)error_msg, (uint32_t)error_value, (const char *)MBED_FILENAME, __LINE__ )
#define MBED_WARNING( error_status, error_msg ) mbed_warning( error_status, (const char *)error_msg, (uint32_t)0 , (const char *)MBED_FILENAME, __LINE__ )
#else
#define MBED_WARNING1( error_status, error_msg, error_value ) mbed_warning( error_status, (const char *)error_msg, (uint32_t)error_value, NULL, 0 )
#define MBED_WARNING( error_status, error_msg ) mbed_warning( error_status, (const char *)error_msg, (uint32_t)0, NULL, 0 )
#endif
#define MBED_WARNING1( error_status, error_msg, error_value ) mbed_warning( error_status, (const char *)NULL, (uint32_t)error_value, NULL, 0 )
#define MBED_WARNING( error_status, error_msg ) mbed_warning( error_status, (const char *)NULL, (uint32_t)0, NULL, 0 )
#else //NDEBUG
#if MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED
#define MBED_WARNING1( error_status, error_msg, error_value ) mbed_warning( error_status, (const char *)error_msg, (uint32_t)error_value, (const char *)MBED_FILENAME, __LINE__ )
#define MBED_WARNING( error_status, error_msg ) mbed_warning( error_status, (const char *)error_msg, (uint32_t)0 , (const char *)MBED_FILENAME, __LINE__ )
#else //MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED
#define MBED_WARNING1( error_status, error_msg, error_value ) mbed_warning( error_status, (const char *)error_msg, (uint32_t)error_value, NULL, 0 )
#define MBED_WARNING( error_status, error_msg ) mbed_warning( error_status, (const char *)error_msg, (uint32_t)0, NULL, 0 )
#endif
#endif
/**
@ -176,16 +183,16 @@ typedef int mbed_error_status_t;
*
*/
#ifdef NDEBUG
#define MBED_ERROR1( error_status, error_msg, error_value ) mbed_error( error_status, (const char *)NULL, (uint32_t)error_value, NULL, 0 )
#define MBED_ERROR( error_status, error_msg ) mbed_error( error_status, (const char *)NULL, (uint32_t)0 , NULL, 0 )
#else
#if defined(MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED)
#define MBED_ERROR1( error_status, error_msg, error_value ) mbed_error( error_status, (const char *)error_msg, (uint32_t)error_value, (const char *)MBED_FILENAME, __LINE__ )
#define MBED_ERROR( error_status, error_msg ) mbed_error( error_status, (const char *)error_msg, (uint32_t)0 , (const char *)MBED_FILENAME, __LINE__ )
#else
#define MBED_ERROR1( error_status, error_msg, error_value ) mbed_error( error_status, (const char *)error_msg, (uint32_t)error_value, NULL, 0 )
#define MBED_ERROR( error_status, error_msg ) mbed_error( error_status, (const char *)error_msg, (uint32_t)0 , NULL, 0 )
#endif
#define MBED_ERROR1( error_status, error_msg, error_value ) mbed_error( error_status, (const char *)NULL, (uint32_t)error_value, NULL, 0 )
#define MBED_ERROR( error_status, error_msg ) mbed_error( error_status, (const char *)NULL, (uint32_t)0 , NULL, 0 )
#else //NDEBUG
#if MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED
#define MBED_ERROR1( error_status, error_msg, error_value ) mbed_error( error_status, (const char *)error_msg, (uint32_t)error_value, (const char *)MBED_FILENAME, __LINE__ )
#define MBED_ERROR( error_status, error_msg ) mbed_error( error_status, (const char *)error_msg, (uint32_t)0 , (const char *)MBED_FILENAME, __LINE__ )
#else //MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED
#define MBED_ERROR1( error_status, error_msg, error_value ) mbed_error( error_status, (const char *)error_msg, (uint32_t)error_value, NULL, 0 )
#define MBED_ERROR( error_status, error_msg ) mbed_error( error_status, (const char *)error_msg, (uint32_t)0 , NULL, 0 )
#endif
#endif
//Error Type definition
@ -253,8 +260,7 @@ typedef enum _mbed_error_type_t
\endverbatim
*
*/
typedef enum _mbed_module_type
{
typedef enum _mbed_module_type {
MBED_MODULE_APPLICATION = 0,
MBED_MODULE_PLATFORM,
MBED_MODULE_KERNEL,
@ -566,8 +572,7 @@ typedef enum _mbed_module_type
\endverbatim
*/
typedef enum _mbed_error_code
{
typedef enum _mbed_error_code {
//Below are POSIX ERROR CODE definitions, which starts at MBED_POSIX_ERROR_BASE(=0)
//POSIX ERROR CODE definitions starts at offset 0(MBED_POSIX_ERROR_BASE) to align them with actual Posix Error Code
//defintions in mbed_retarget.h
@ -812,8 +817,8 @@ typedef struct _mbed_error_ctx {
uint32_t thread_stack_size;
uint32_t thread_stack_mem;
uint32_t thread_current_sp;
#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED
char error_filename[MBED_CONF_MAX_ERROR_FILENAME_LEN];
#ifdef MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN
char error_filename[MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN];
uint32_t error_line_number;
#endif
} mbed_error_ctx;

View File

@ -21,22 +21,22 @@
#include "platform/mbed_critical.h"
#include "platform/mbed_interface.h"
#ifndef MBED_CONF_ERROR_HIST_DISABLED
#if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
#include "platform/mbed_error_hist.h"
static mbed_error_ctx mbed_error_ctx_log[MBED_CONF_ERROR_HIST_SIZE] = {0};
static mbed_error_ctx mbed_error_ctx_log[MBED_CONF_PLATFORM_ERROR_HIST_SIZE] = {0};
static int error_log_count = -1;
mbed_error_status_t mbed_error_hist_put(mbed_error_ctx *error_ctx)
{
//Return error if error_ctx is NULL
if(NULL == error_ctx) {
if (NULL == error_ctx) {
return MBED_ERROR_INVALID_ARGUMENT;
}
core_util_critical_section_enter();
error_log_count++;
memcpy(&mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_HIST_SIZE], error_ctx, sizeof(mbed_error_ctx) );
memcpy(&mbed_error_ctx_log[error_log_count % MBED_CONF_PLATFORM_ERROR_HIST_SIZE], error_ctx, sizeof(mbed_error_ctx));
core_util_critical_section_exit();
return MBED_SUCCESS;
@ -45,17 +45,17 @@ mbed_error_status_t mbed_error_hist_put(mbed_error_ctx *error_ctx)
mbed_error_status_t mbed_error_hist_get(int index, mbed_error_ctx *error_ctx)
{
//Return error if index is more than max log size
if(index >= MBED_CONF_ERROR_HIST_SIZE) {
if (index >= MBED_CONF_PLATFORM_ERROR_HIST_SIZE) {
return MBED_ERROR_INVALID_ARGUMENT;
}
core_util_critical_section_enter();
//calculate the index where we want to pick the ctx
if(error_log_count >= MBED_CONF_ERROR_HIST_SIZE) {
index = (error_log_count + index + 1) % MBED_CONF_ERROR_HIST_SIZE;
if (error_log_count >= MBED_CONF_PLATFORM_ERROR_HIST_SIZE) {
index = (error_log_count + index + 1) % MBED_CONF_PLATFORM_ERROR_HIST_SIZE;
}
core_util_critical_section_exit();
memcpy(error_ctx, &mbed_error_ctx_log[index % MBED_CONF_ERROR_HIST_SIZE], sizeof(mbed_error_ctx) );
memcpy(error_ctx, &mbed_error_ctx_log[index % MBED_CONF_PLATFORM_ERROR_HIST_SIZE], sizeof(mbed_error_ctx));
return MBED_SUCCESS;
}
@ -64,7 +64,7 @@ mbed_error_ctx *mbed_error_hist_get_entry(void)
{
core_util_critical_section_enter();
error_log_count++;
mbed_error_ctx *ctx = &mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_HIST_SIZE];
mbed_error_ctx *ctx = &mbed_error_ctx_log[error_log_count % MBED_CONF_PLATFORM_ERROR_HIST_SIZE];
core_util_critical_section_exit();
return ctx;
@ -72,11 +72,11 @@ mbed_error_ctx *mbed_error_hist_get_entry(void)
mbed_error_status_t mbed_error_hist_get_last_error(mbed_error_ctx *error_ctx)
{
if(-1 == error_log_count) {
if (-1 == error_log_count) {
return MBED_ERROR_ITEM_NOT_FOUND;
}
core_util_critical_section_enter();
memcpy(error_ctx, &mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_HIST_SIZE], sizeof(mbed_error_ctx) );
memcpy(error_ctx, &mbed_error_ctx_log[error_log_count % MBED_CONF_PLATFORM_ERROR_HIST_SIZE], sizeof(mbed_error_ctx));
core_util_critical_section_exit();
return MBED_SUCCESS;
@ -84,7 +84,7 @@ mbed_error_status_t mbed_error_hist_get_last_error(mbed_error_ctx *error_ctx)
int mbed_error_hist_get_count()
{
return (error_log_count >= MBED_CONF_ERROR_HIST_SIZE? MBED_CONF_ERROR_HIST_SIZE:error_log_count+1);
return (error_log_count >= MBED_CONF_PLATFORM_ERROR_HIST_SIZE? MBED_CONF_PLATFORM_ERROR_HIST_SIZE:error_log_count+1);
}
mbed_error_status_t mbed_error_hist_reset()

View File

@ -16,11 +16,11 @@
#ifndef MBED_ERROR_HIST_H
#define MBED_ERROR_HIST_H
#ifndef MBED_CONF_ERROR_HIST_SIZE
#define MBED_CONF_ERROR_HIST_SIZE 4
#ifndef MBED_CONF_PLATFORM_ERROR_HIST_SIZE
#define MBED_CONF_PLATFORM_ERROR_HIST_SIZE 4
#else
#if MBED_CONF_ERROR_HIST_SIZE == 0
#define MBED_CONF_ERROR_HIST_SIZE 1
#if MBED_CONF_PLATFORM_ERROR_HIST_SIZE == 0
#define MBED_CONF_PLATFORM_ERROR_HIST_SIZE 1
#endif
#endif

View File

@ -39,6 +39,31 @@
"poll-use-lowpower-timer": {
"help": "Enable use of low power timer class for poll(). May cause missing events.",
"value": false
},
"error-hist-enabled": {
"help": "Enable for error history tracking.",
"value": false
},
"error-hist-size": {
"help": "Set the number of most recent errors the system keeps in its history, needs error-hist-enabled set to true for this to work.",
"value": 4
},
"error-filename-capture-enabled": {
"help": "Enables capture of filename and line number as part of error context capture, this works only for debug and develop builds. On release builds, filename capture is always disabled",
"value": false
},
"error-all-threads-info": {
"help": "Reports all the threads in the system as part of error report.",
"value": false
},
"max-error-filename-len": {
"help": "Sets the maximum length of buffer used for capturing the filename in error context. This needs error-filename-capture-enabled feature.",
"value": 16
}
},
"target_overrides": {

View File

@ -17,278 +17,117 @@
#include "rtx_os.h"
#include "device.h"
#include "platform/mbed_error.h"
#include "platform/mbed_interface.h"
#include "hal/serial_api.h"
#include "hal/itm_api.h"
#ifndef MBED_FAULT_HANDLER_DISABLED
#include "mbed_rtx_fault_handler.h"
#ifdef DEVICE_SERIAL
extern int stdio_uart_inited;
extern serial_t stdio_uart;
#endif
//Functions Prototypes
void print_context_info(void);
//Global for populating the context in exception handler
mbed_fault_context_t mbed_fault_context;
/* Converts a uint32 to hex char string */
static void value_to_hex_str(uint32_t value, char *hex_str)
{
char hex_char_map[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
int i = 0;
//Return without converting if hex_str is not provided
if(hex_str == NULL) return;
for(i=7; i>=0; i--) {
hex_str[i] = hex_char_map[(value & (0xf << (i * 4))) >> (i * 4)];
}
}
static void fault_print_init(void)
{
#if DEVICE_SERIAL
/* Initializes std uart if not init-ed yet */
if (!stdio_uart_inited) {
serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
}
#endif
#if DEVICE_ITM
/*Initialize ITM interfaces*/
mbed_itm_init();
#endif
}
static void fault_putc(char ch)
{
#if DEVICE_SERIAL
serial_putc(&stdio_uart, ch);
#endif
#if DEVICE_ITM
/*Initialize ITM interfaces*/
mbed_itm_send(ITM_PORT_SWO, ch);
#endif
}
/* Limited print functionality which prints the string out to
stdout/uart without using stdlib by directly calling serial-api
and also uses less resources
The fmtstr contains the format string for printing and for every %
found in that it fetches a uint32 value from values buffer
and prints it in hex format.
*/
static void fault_print(char *fmtstr, uint32_t *values)
{
#if DEVICE_SERIAL || DEVICE_ITM
int i = 0;
int idx = 0;
int vidx = 0;
char num_str[9]={0};
char *str=NULL;
//Init error reporting interfaces
fault_print_init();
while(fmtstr[i] != '\0') {
if(fmtstr[i]=='%') {
i++;
if(fmtstr[i]=='x') {
//print the number in hex format
value_to_hex_str(values[vidx++],num_str);
for(idx=7; idx>=0; idx--) {
fault_putc(num_str[idx]);
}
}
else if(fmtstr[i]=='s') {
//print the string
str = (char *)((uint32_t)values[vidx++]);
while(*str != '\0') {
fault_putc(*str);
str++;
}
str = NULL;
} else {
//Do not handle any other % formatting and keep going
}
} else {
//handle carriage returns
if (fmtstr[i] == '\n') {
fault_putc('\r');
}
fault_putc(fmtstr[i]);
}
i++;
}
#endif
}
#ifdef MBED_CONF_RTOS_PRESENT
/* Prints info of a thread(using osRtxThread_t struct)*/
static void print_thread(osRtxThread_t *thread)
{
uint32_t data[5];
data[0]=thread->state;
data[1]=thread->thread_addr;
data[2]=thread->stack_size;
data[3]=(uint32_t)thread->stack_mem;
data[4]=thread->sp;
fault_print("\nState: 0x%x Entry: 0x%x Stack Size: 0x%x Mem: 0x%x SP: 0x%x", data);
}
/* Prints thread info from a list */
static void print_threads_info(osRtxThread_t *threads)
{
while(threads != NULL) {
print_thread( threads );
threads = threads->thread_next;
}
}
#endif
//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.
__NO_RETURN void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_context_in, void *osRtxInfoIn)
void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_context_in, void *osRtxInfoIn)
{
mbed_error_status_t faultStatus = MBED_SUCCESS;
fault_print("\n++ MbedOS Fault Handler ++\n\nFaultType: ",NULL);
mbed_error_printf("\n++ MbedOS Fault Handler ++\n\nFaultType: ");
switch( fault_type ) {
case HARD_FAULT_EXCEPTION:
fault_print("HardFault",NULL);
faultStatus = MBED_ERROR_HARDFAULT_EXCEPTION;
break;
case MEMMANAGE_FAULT_EXCEPTION:
fault_print("MemManageFault",NULL);
mbed_error_printf("MemManageFault");
faultStatus = MBED_ERROR_MEMMANAGE_EXCEPTION;
break;
case BUS_FAULT_EXCEPTION:
fault_print("BusFault",NULL);
mbed_error_printf("BusFault");
faultStatus = MBED_ERROR_BUSFAULT_EXCEPTION;
break;
case USAGE_FAULT_EXCEPTION:
fault_print("UsageFault",NULL);
mbed_error_printf("UsageFault");
faultStatus = MBED_ERROR_USAGEFAULT_EXCEPTION;
break;
default:
fault_print("Unknown Fault",NULL);
faultStatus = MBED_ERROR_UNKNOWN;
//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;
}
fault_print("\n\nContext:",NULL);
mbed_error_printf("\n\nContext:");
print_context_info();
fault_print("\n\nThreads Info:\nCurrent:",NULL);
print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.curr);
fault_print("\nNext:",NULL);
print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.next);
fault_print("\nWait:",NULL);
osRtxThread_t *threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.wait_list;
print_threads_info(threads);
fault_print("\nDelay:",NULL);
threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.delay_list;
print_threads_info(threads);
fault_print("\nIdle:",NULL);
threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.idle;
print_threads_info(threads);
fault_print("\n\n-- MbedOS Fault Handler --\n\n",NULL);
mbed_error_printf("\n\n-- MbedOS Fault Handler --\n\n");
//Now call mbed_error, to log the error and halt the system
mbed_error( MBED_MAKE_ERROR( MBED_MODULE_UNKNOWN, faultStatus ), "System encountered an unrecoverable fault exception, halting system.", mbed_fault_context.PC_reg, NULL, 0 );
mbed_error( faultStatus, "Unrecoverable fault excaption.", mbed_fault_context.PC_reg, NULL, 0 );
/* In case we return, just spin here, we have already crashed */
for (;;) {
__WFI();
}
}
void print_context_info(void)
MBED_NOINLINE void print_context_info(void)
{
//Context Regs
fault_print("\nR0 : %x"
"\nR1 : %x"
"\nR2 : %x"
"\nR3 : %x"
"\nR4 : %x"
"\nR5 : %x"
"\nR6 : %x"
"\nR7 : %x"
"\nR8 : %x"
"\nR9 : %x"
"\nR10 : %x"
"\nR11 : %x"
"\nR12 : %x"
"\nSP : %x"
"\nLR : %x"
"\nPC : %x"
"\nxPSR : %x"
"\nPSP : %x"
"\nMSP : %x", (uint32_t *)&mbed_fault_context);
for(int i=0;i<13;i++) {
mbed_error_printf("\nR%-4d: %08X", i, ((uint32_t *)&mbed_fault_context)[i]);
}
mbed_error_printf("\nSP : %08X"
"\nLR : %08X"
"\nPC : %08X"
"\nxPSR : %08X"
"\nPSP : %08X"
"\nMSP : %08X", mbed_fault_context.SP_reg, mbed_fault_context.LR_reg, mbed_fault_context.PC_reg,
mbed_fault_context.xPSR, mbed_fault_context.PSP, mbed_fault_context.MSP );
//Capture CPUID to get core/cpu info
fault_print("\nCPUID: %x",(uint32_t *)&SCB->CPUID);
mbed_error_printf("\nCPUID: %08X", SCB->CPUID);
#if !defined(TARGET_M0) && !defined(TARGET_M0P)
//Capture fault information registers to infer the cause of exception
uint32_t FSR[7] = {0};
FSR[0] = SCB->HFSR;
//Split/Capture CFSR into MMFSR, BFSR, UFSR
FSR[1] = 0xFF & SCB->CFSR;//MMFSR
FSR[2] = (0xFF00 & SCB->CFSR) >> 8;//BFSR
FSR[3] = (0xFFFF0000 & SCB->CFSR) >> 16;//UFSR
FSR[4] = SCB->DFSR;
FSR[5] = SCB->AFSR;
FSR[6] = SCB->SHCSR;
fault_print("\nHFSR : %x"
"\nMMFSR: %x"
"\nBFSR : %x"
"\nUFSR : %x"
"\nDFSR : %x"
"\nAFSR : %x"
"\nSHCSR: %x",FSR);
mbed_error_printf("\nHFSR : %08X"
"\nMMFSR: %08X"
"\nBFSR : %08X"
"\nUFSR : %08X"
"\nDFSR : %08X"
"\nAFSR : %08X" ////Split/Capture CFSR into MMFSR, BFSR, UFSR
,SCB->HFSR, (0xFF & SCB->CFSR), ((0xFF00 & SCB->CFSR) >> 8), ((0xFFFF0000 & SCB->CFSR) >> 16), SCB->DFSR, SCB->AFSR );
//Print MMFAR only if its valid as indicated by MMFSR
if(FSR[1] & 0x80) {
fault_print("\nMMFAR: %x",(uint32_t *)&SCB->MMFAR);
if ((0xFF & SCB->CFSR) & 0x80) {
mbed_error_printf("\nMMFAR: %08X",SCB->MMFAR);
}
//Print BFAR only if its valid as indicated by BFSR
if(FSR[2] & 0x80) {
fault_print("\nBFAR : %x",(uint32_t *)&SCB->BFAR);
if (((0xFF00 & SCB->CFSR) >> 8) & 0x80) {
mbed_error_printf("\nBFAR : %08X",SCB->BFAR);
}
#endif
//Print Mode
if(mbed_fault_context.EXC_RETURN & 0x8) {
fault_print("\nMode : Thread", NULL);
if (mbed_fault_context.EXC_RETURN & 0x8) {
mbed_error_printf("\nMode : Thread");
//Print Priv level in Thread mode - We capture CONTROL reg which reflects the privilege.
//Note that the CONTROL register captured still reflects the privilege status of the
//thread mode eventhough we are in Handler mode by the time we capture it.
if(mbed_fault_context.CONTROL & 0x1) {
fault_print("\nPriv : User", NULL);
mbed_error_printf("\nPriv : User");
} else {
fault_print("\nPriv : Privileged", NULL);
mbed_error_printf("\nPriv : Privileged");
}
} else {
fault_print("\nMode : Handler", NULL);
fault_print("\nPriv : Privileged", NULL);
mbed_error_printf("\nMode : Handler");
mbed_error_printf("\nPriv : Privileged");
}
//Print Return Stack
if(mbed_fault_context.EXC_RETURN & 0x4) {
fault_print("\nStack: PSP", NULL);
if (mbed_fault_context.EXC_RETURN & 0x4) {
mbed_error_printf("\nStack: PSP");
} else {
fault_print("\nStack: MSP", NULL);
mbed_error_printf("\nStack: MSP");
}
}

View File

@ -53,6 +53,6 @@ typedef struct {
//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.
__NO_RETURN void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_context_in, void *osRtxInfoIn);
void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_context_in, void *osRtxInfoIn);
#endif