diff --git a/TESTS/mbed_platform/error_handling/main.cpp b/TESTS/mbed_platform/error_handling/main.cpp index 2498964c50..05b10f37d2 100644 --- a/TESTS/mbed_platform/error_handling/main.cpp +++ b/TESTS/mbed_platform/error_handling/main.cpp @@ -33,13 +33,13 @@ void test_error_count_and_reset() MBED_WARNING(MBED_ERROR_OUT_OF_MEMORY, "Out of memory", i); } - TEST_ASSERT_EQUAL_INT(count, get_error_count()); + TEST_ASSERT_EQUAL_INT(count, mbed_get_error_count()); //clear the errors and error count to 0 mbed_clear_all_errors(); //Now the error count should be 0 - TEST_ASSERT_EQUAL_INT(0, get_error_count()); + TEST_ASSERT_EQUAL_INT(0, mbed_get_error_count()); } @@ -54,61 +54,61 @@ void test_error_capturing() //first clear all errors and start afresh MBED_WARNING(MBED_ERROR_OUT_OF_RESOURCES, "System type error", 0x1100 ); - mbed_error_status_t lastError = get_last_error(); + mbed_error_status_t lastError = mbed_get_last_error(); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_SYSTEM, MBED_GET_ERROR_TYPE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_MODULE_UNKNOWN, MBED_GET_ERROR_MODULE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_OUT_OF_RESOURCES, MBED_GET_ERROR_CODE(lastError)); mbed_error_status_t error = MBED_MAKE_ERROR(MBED_MODULE_DRIVER_SERIAL, MBED_ERROR_CODE_OUT_OF_RESOURCES); MBED_WARNING(error, "Error Serial", 0xAA ); - lastError = get_last_error(); + lastError = mbed_get_last_error(); TEST_ASSERT_EQUAL_UINT(error, lastError); error = MBED_MAKE_CUSTOM_ERROR(MBED_MODULE_APPLICATION, MBED_ERROR_CODE_UNKNOWN); MBED_WARNING(error, "Custom Error Unknown", 0x1234 ); - lastError = get_last_error(); + lastError = mbed_get_last_error(); TEST_ASSERT_EQUAL_UINT(error, lastError); MBED_WARNING(MBED_ERROR_EPERM, "Posix Error Eperm", 0x1234 ); - lastError = get_last_error(); + lastError = mbed_get_last_error(); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_EPERM, lastError); error = MBED_MAKE_CUSTOM_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_CREATE_FAILED); MBED_WARNING(error, "Custom Error Type", error_value); - lastError = get_last_error(); + lastError = mbed_get_last_error(); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_CUSTOM, MBED_GET_ERROR_TYPE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_MODULE_PLATFORM, MBED_GET_ERROR_MODULE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_CREATE_FAILED, MBED_GET_ERROR_CODE(lastError)); - mbed_error_status_t status = mbed_get_last_error_log_info( &error_ctx ); + mbed_error_status_t status = mbed_get_last_error_info( &error_ctx ); TEST_ASSERT(status == MBED_SUCCESS); TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value); error_value = 0xAABBCC; MBED_WARNING(MBED_ERROR_EACCES, "Posix Error", error_value ); - lastError = get_last_error(); + lastError = mbed_get_last_error(); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_POSIX, MBED_GET_ERROR_TYPE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_MODULE_UNKNOWN, MBED_GET_ERROR_MODULE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_EACCES, MBED_GET_ERROR_CODE(lastError)); - status = mbed_get_last_error_log_info( &error_ctx ); + status = mbed_get_last_error_info( &error_ctx ); TEST_ASSERT(status == MBED_SUCCESS); TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value); error_value = 0; error = MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_UNKNOWN); MBED_WARNING(error, "HAL Entity error", error_value ); - lastError = get_last_error(); + lastError = mbed_get_last_error(); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_SYSTEM, MBED_GET_ERROR_TYPE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_MODULE_HAL, MBED_GET_ERROR_MODULE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_UNKNOWN, MBED_GET_ERROR_CODE(lastError)); - status = mbed_get_last_error_log_info( &error_ctx ); + status = mbed_get_last_error_info( &error_ctx ); TEST_ASSERT(status == MBED_SUCCESS); TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value); MBED_WARNING(MBED_ERROR_MUTEX_LOCK_FAILED, "Mutex lock failed", 0x4455 ); - error = get_last_error(); + error = mbed_get_last_error(); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_MUTEX_LOCK_FAILED, error); - error = get_first_error(); + error = mbed_get_first_error(); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_OUT_OF_RESOURCES, error); } @@ -121,7 +121,7 @@ void test_error_context_capture() mbed_error_ctx error_ctx = {0}; MBED_WARNING(MBED_ERROR_INVALID_ARGUMENT, "System type error", error_value ); - mbed_error_status_t status = mbed_get_last_error_log_info( &error_ctx ); + mbed_error_status_t status = mbed_get_last_error_info( &error_ctx ); TEST_ASSERT(status == MBED_SUCCESS); TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value); TEST_ASSERT_EQUAL_UINT(osThreadGetId(), error_ctx.thread_id); @@ -136,7 +136,7 @@ void test_error_context_capture() #endif } -#ifndef MBED_CONF_ERROR_LOG_DISABLED +#ifndef MBED_CONF_ERROR_HIST_DISABLED /** Test error logging functionality */ void test_error_logging() @@ -151,15 +151,15 @@ void test_error_logging() MBED_WARNING(MBED_ERROR_INVALID_SIZE, "Invalid size", 2 ); MBED_WARNING(MBED_ERROR_INVALID_FORMAT, "Invalid format", 3 ); - mbed_error_status_t status = mbed_get_error_log_info( 0, &error_ctx ); + mbed_error_status_t status = mbed_get_error_hist_info( 0, &error_ctx ); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_ARGUMENT, error_ctx.error_status); TEST_ASSERT_EQUAL_UINT(1, error_ctx.error_value); - status = mbed_get_error_log_info( 1, &error_ctx ); + status = mbed_get_error_hist_info( 1, &error_ctx ); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_SIZE, error_ctx.error_status); TEST_ASSERT_EQUAL_UINT(2, error_ctx.error_value); - status = mbed_get_error_log_info( 2, &error_ctx ); + status = mbed_get_error_hist_info( 2, &error_ctx ); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_FORMAT, error_ctx.error_status); TEST_ASSERT_EQUAL_UINT(3, error_ctx.error_value); @@ -175,24 +175,24 @@ void test_error_logging() MBED_WARNING(MBED_ERROR_UNSUPPORTED, "Not supported", 12 ); MBED_WARNING(MBED_ERROR_ACCESS_DENIED, "Access denied", 13 ); - status = mbed_get_error_log_info( 0, &error_ctx ); + status = mbed_get_error_hist_info( 0, &error_ctx ); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TIME_OUT, error_ctx.error_status); TEST_ASSERT_EQUAL_UINT(10, error_ctx.error_value); - status = mbed_get_error_log_info( 1, &error_ctx ); + status = mbed_get_error_hist_info( 1, &error_ctx ); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_ALREADY_IN_USE, error_ctx.error_status); TEST_ASSERT_EQUAL_UINT(11, error_ctx.error_value); - status = mbed_get_error_log_info( 2, &error_ctx ); + status = mbed_get_error_hist_info( 2, &error_ctx ); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_UNSUPPORTED, error_ctx.error_status); TEST_ASSERT_EQUAL_UINT(12, error_ctx.error_value); - status = mbed_get_error_log_info( 3, &error_ctx ); + status = mbed_get_error_hist_info( 3, &error_ctx ); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_ACCESS_DENIED, error_ctx.error_status); TEST_ASSERT_EQUAL_UINT(13, error_ctx.error_value); //Try an index which is invalid, we should get ERROR_INVALID_ARGUMENT back - status = mbed_get_error_log_info( 99, &error_ctx ); + status = mbed_get_error_hist_info( 99, &error_ctx ); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_ARGUMENT, status); } @@ -202,7 +202,6 @@ void test_error_logging() //Error logger threads void err_thread_func(mbed_error_status_t *error_status) { - //printf("\nError Status = 0x%08X\n",*error_status); MBED_WARNING(*error_status, "Error from Multi-Threaded error logging test", *error_status ); } @@ -228,15 +227,14 @@ void test_error_logging_multithread() errThread[i]->join(); } - i = mbed_get_error_log_count()-1; - //printf("\nError log count = %d\n", i+1); + i = mbed_get_error_hist_count()-1; + for(;i>=0;--i) { - mbed_error_status_t status = mbed_get_error_log_info( i, &error_ctx ); + mbed_error_status_t status = mbed_get_error_hist_info( i, &error_ctx ); if(status != MBED_SUCCESS) { TEST_FAIL(); } - //printf("\nError Status[%d] = 0x%08X Value = 0x%08X\n", i, (unsigned int)error_ctx.error_status, (unsigned int)error_ctx.error_value); TEST_ASSERT_EQUAL_UINT((unsigned int)error_ctx.error_value, (unsigned int)error_ctx.error_status); } } @@ -307,25 +305,21 @@ void test_save_error_log() error = MBED_TEST_FILESYSTEM::format(&fd); if(error < 0) { - printf("Failed formatting"); - TEST_FAIL(); + TEST_FAIL_MESSAGE("Failed formatting"); } error = fs.mount(&fd); if(error < 0) { - printf("Failed mounting fs"); - TEST_FAIL(); + TEST_FAIL_MESSAGE("Failed mounting fs"); } - if(MBED_SUCCESS != mbed_save_error_log("/fs/errors.log")) { - printf("Failed saving error log"); - TEST_FAIL(); + if(MBED_SUCCESS != mbed_save_error_hist("/fs/errors.log")) { + TEST_FAIL_MESSAGE("Failed saving error log"); } FILE *error_file = fopen("/fs/errors.log", "r"); if(error_file == NULL) { - printf("Unable to find error log in fs"); - TEST_FAIL(); + TEST_FAIL_MESSAGE("Unable to find error log in fs"); } char buff[64] = {0}; @@ -333,13 +327,11 @@ void test_save_error_log() int size = fread(&buff[0], 1, 15, error_file); fwrite(&buff[0], 1, size, stdout); } - printf("\r\n"); fclose(error_file); error = fs.unmount(); if(error < 0) { - printf("Failed unmounting fs"); - TEST_FAIL(); + TEST_FAIL_MESSAGE("Failed unmounting fs"); } } @@ -347,7 +339,7 @@ void test_save_error_log() utest::v1::status_t test_setup(const size_t number_of_cases) { - GREENTEA_SETUP(300, "default_auto"); + GREENTEA_SETUP(120, "default_auto"); return utest::v1::verbose_test_setup_handler(number_of_cases); } @@ -356,7 +348,7 @@ Case cases[] = { Case("Test error encoding, value capture, first and last errors", test_error_capturing), Case("Test error context capture", test_error_context_capture), Case("Test error hook", test_error_hook), -#ifndef MBED_CONF_ERROR_LOG_DISABLED +#ifndef MBED_CONF_ERROR_HIST_DISABLED Case("Test error logging", test_error_logging), Case("Test error handling multi-threaded", test_error_logging_multithread), #ifdef MBED_TEST_SIM_BLOCKDEVICE diff --git a/features/FEATURE_LWIP/lwip-interface/lwip-sys/arch/lwip_sys_arch.c b/features/FEATURE_LWIP/lwip-interface/lwip-sys/arch/lwip_sys_arch.c index 74cc488ff2..f46d5e6133 100644 --- a/features/FEATURE_LWIP/lwip-interface/lwip-sys/arch/lwip_sys_arch.c +++ b/features/FEATURE_LWIP/lwip-interface/lwip-sys/arch/lwip_sys_arch.c @@ -123,7 +123,7 @@ u32_t sys_now(void) { *---------------------------------------------------------------------------*/ err_t sys_mbox_new(sys_mbox_t *mbox, int queue_sz) { if (queue_sz > MB_SIZE) - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_INVALID_SIZE), "sys_mbox_new size error\n", queue_sz); + error("sys_mbox_new size error\n"); memset(mbox, 0, sizeof(*mbox)); @@ -131,7 +131,7 @@ err_t sys_mbox_new(sys_mbox_t *mbox, int queue_sz) { mbox->attr.cb_size = sizeof(mbox->data); mbox->id = osEventFlagsNew(&mbox->attr); if (mbox->id == NULL) - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_CREATE_FAILED), "sys_mbox_new create error\n", mbox->id); + error("sys_mbox_new create error\n"); osEventFlagsSet(mbox->id, SYS_MBOX_POST_EVENT); @@ -150,7 +150,7 @@ err_t sys_mbox_new(sys_mbox_t *mbox, int queue_sz) { *---------------------------------------------------------------------------*/ void sys_mbox_free(sys_mbox_t *mbox) { if (mbox->post_idx != mbox->fetch_idx) - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_FREE_FAILED), "sys_mbox_free error\n", mbox->post_idx); + error("sys_mbox_free error\n"); } /*---------------------------------------------------------------------------* @@ -309,7 +309,7 @@ err_t sys_sem_new(sys_sem_t *sem, u8_t count) { sem->attr.cb_size = sizeof(sem->data); sem->id = osSemaphoreNew(UINT16_MAX, count, &sem->attr); if (sem->id == NULL) - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_CREATE_FAILED), "sys_sem_new create error\n", sem->id); + error("sys_sem_new create error\n"); return ERR_OK; } @@ -388,14 +388,14 @@ err_t sys_mutex_new(sys_mutex_t *mutex) { * @param mutex the mutex to lock */ void sys_mutex_lock(sys_mutex_t *mutex) { if (osMutexAcquire(mutex->id, osWaitForever) != osOK) - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "sys_mutex_lock error\n", mutex->id); + error("sys_mutex_lock error\n"); } /** Unlock a mutex * @param mutex the mutex to unlock */ void sys_mutex_unlock(sys_mutex_t *mutex) { if (osMutexRelease(mutex->id) != osOK) - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_MUTEX_UNLOCK_FAILED), "sys_mutex_unlock error\n", mutex->id); + error("sys_mutex_unlock error\n"); } /** Delete a mutex @@ -418,7 +418,7 @@ void sys_init(void) { lwip_sys_mutex_attr.cb_size = sizeof(lwip_sys_mutex_data); lwip_sys_mutex = osMutexNew(&lwip_sys_mutex_attr); if (lwip_sys_mutex == NULL) - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_INITIALIZATION_FAILED), "sys_init error\n", lwip_sys_mutex); + error("sys_init error\n"); } /*---------------------------------------------------------------------------* @@ -452,7 +452,7 @@ u32_t sys_jiffies(void) { *---------------------------------------------------------------------------*/ sys_prot_t sys_arch_protect(void) { if (osMutexAcquire(lwip_sys_mutex, osWaitForever) != osOK) - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "sys_arch_protect error\n", lwip_sys_mutex); + error("sys_arch_protect error\n"); return (sys_prot_t) 1; } @@ -469,7 +469,7 @@ sys_prot_t sys_arch_protect(void) { *---------------------------------------------------------------------------*/ void sys_arch_unprotect(sys_prot_t p) { if (osMutexRelease(lwip_sys_mutex) != osOK) - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "sys_arch_unprotect error\n", lwip_sys_mutex); + error("sys_arch_unprotect error\n"); } u32_t sys_now(void) { @@ -508,7 +508,7 @@ sys_thread_t sys_thread_new(const char *pcName, LWIP_DEBUGF(SYS_DEBUG, ("New Thread: %s\n", pcName)); if (thread_pool_index >= SYS_THREAD_POOL_N) - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_THREAD_CREATE_FAILED), "sys_thread_new number error\n", thread_pool_index); + error("sys_thread_new number error\n"); sys_thread_t t = (sys_thread_t)&thread_pool[thread_pool_index]; thread_pool_index++; @@ -520,11 +520,11 @@ sys_thread_t sys_thread_new(const char *pcName, t->attr.stack_size = stacksize; t->attr.stack_mem = malloc(stacksize); if (t->attr.stack_mem == NULL) { - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_OUT_OF_MEMORY), "Error allocating the stack memory", t); + error("Error allocating the stack memory"); } t->id = osThreadNew((osThreadFunc_t)thread, arg, &t->attr); if (t->id == NULL) - MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_THREAD_CREATE_FAILED), "sys_thread_new create error\n", t->id); + error("sys_thread_new create error\n"); return t; } diff --git a/platform/mbed_error.c b/platform/mbed_error.c index 29423b90e3..c191feae2e 100644 --- a/platform/mbed_error.c +++ b/platform/mbed_error.c @@ -18,25 +18,43 @@ #include "device.h" #include "platform/mbed_critical.h" #include "platform/mbed_error.h" -#include "platform/mbed_error_log.h" -#include "platform/mbed_error_report.h" +#include "platform/mbed_error_hist.h" #include "platform/mbed_interface.h" +#ifdef MBED_CONF_RTOS_PRESENT +#include "rtx_os.h" +#endif #if DEVICE_STDIO_MESSAGES #include #endif +//Helper macro to get the current SP +#define GET_CURRENT_SP(sp) \ + { \ + /*If in Handler mode we are always using MSP*/ \ + if( __get_IPSR() != 0U ) { \ + sp = __get_MSP(); \ + } else { \ + /*Look into CONTROL.SPSEL value*/ \ + if ((__get_CONTROL() & 2U) == 0U) { \ + sp = __get_MSP();/*Read MSP*/ \ + } else { \ + sp = __get_PSP();/*Read PSP*/ \ + } \ + } \ + } + + static uint8_t error_in_progress = 0; static int error_count = 0; static mbed_error_ctx first_error_ctx = {0}; static mbed_error_ctx last_error_ctx = {0}; static mbed_error_hook_t error_hook = NULL; +static void print_error_report(mbed_error_ctx *ctx, const char *); //Helper function to halt the system static void mbed_halt_system(void) { - mbed_error_print("\nFATAL ERROR: Halting System...\n", NULL); - //If not in ISR context exit, otherwise spin on WFI if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) { for(;;) { @@ -60,6 +78,7 @@ WEAK void error(const char* format, ...) { va_list arg; va_start(arg, format); mbed_error_vfprintf(format, arg); + MBED_ERROR(MBED_ERROR_UNKNOWN, "Fatal Run-time Error", 0); va_end(arg); #endif exit(1); @@ -78,7 +97,7 @@ mbed_error_status_t handle_error(mbed_error_status_t error_status, const char *e } //Prevent corruption by holding out other callers - //and we also need this until we remove the error call completely + //and we also need this until we remove the "error" call completely while (error_in_progress == 1); //Use critsect here, as we don't want inadvertant modification of this global variable @@ -95,6 +114,18 @@ mbed_error_status_t handle_error(mbed_error_status_t error_status, const char *e current_error_ctx.error_status = error_status; current_error_ctx.error_address = (uint32_t)MBED_CALLER_ADDR(); current_error_ctx.error_value = error_value; +#ifdef MBED_CONF_RTOS_PRESENT + //Capture thread info + osRtxThread_t *current_thread = osRtxInfo.thread.run.curr; + current_error_ctx.thread_id = (uint32_t)current_thread; + current_error_ctx.thread_entry_address = (uint32_t)current_thread->thread_addr; + current_error_ctx.thread_stack_size = current_thread->stack_size; + current_error_ctx.thread_stack_mem = (uint32_t)current_thread->stack_mem; +#ifdef TARGET_CORTEX_M + GET_CURRENT_SP(current_error_ctx.thread_current_sp); +#endif //TARGET_CORTEX_M + +#endif //MBED_CONF_RTOS_PRESENT #ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED //Capture filename/linenumber if provided @@ -110,9 +141,6 @@ mbed_error_status_t handle_error(mbed_error_status_t error_status, const char *e } #endif - //Report the error - mbed_report_error(¤t_error_ctx, (char *)error_msg); - //Capture the fist system error and store it if(error_count == 1) { //first error memcpy(&first_error_ctx, ¤t_error_ctx, sizeof(mbed_error_ctx)); @@ -121,9 +149,9 @@ mbed_error_status_t handle_error(mbed_error_status_t error_status, const char *e //copy this error to last error memcpy(&last_error_ctx, ¤t_error_ctx, sizeof(mbed_error_ctx)); -#ifndef MBED_CONF_ERROR_LOG_DISABLED +#ifndef MBED_CONF_ERROR_HIST_DISABLED //Log the error with error log - mbed_log_put_error(¤t_error_ctx); + mbed_error_hist_put(¤t_error_ctx); #endif //Call the error hook if available @@ -137,21 +165,21 @@ mbed_error_status_t handle_error(mbed_error_status_t error_status, const char *e } //Return the first error -mbed_error_status_t get_first_error(void) +mbed_error_status_t mbed_get_first_error(void) { //return the first error recorded return first_error_ctx.error_status; } //Return the last error -mbed_error_status_t get_last_error(void) +mbed_error_status_t mbed_get_last_error(void) { //return the last error recorded return last_error_ctx.error_status; } //Gets the current error count -int get_error_count(void) +int mbed_get_error_count(void) { //return the current error count return error_count; @@ -169,6 +197,9 @@ WEAK mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char //set the error reported and then halt the system if( MBED_SUCCESS != handle_error(error_status, error_msg, error_value, filename, line_number) ) return MBED_ERROR_FAILED_OPERATION; + + //On fatal errors print the error context/report + print_error_report(&last_error_ctx, error_msg); mbed_halt_system(); return MBED_ERROR_FAILED_OPERATION; @@ -187,14 +218,14 @@ mbed_error_status_t mbed_set_error_hook(mbed_error_hook_t error_hook_in) } //Retrieve the first error context from error log -mbed_error_status_t mbed_get_first_error_log_info (mbed_error_ctx *error_info) +mbed_error_status_t mbed_get_first_error_info (mbed_error_ctx *error_info) { memcpy(error_info, &first_error_ctx, sizeof(first_error_ctx)); return MBED_SUCCESS; } //Retrieve the last error context from error log -mbed_error_status_t mbed_get_last_error_log_info (mbed_error_ctx *error_info) +mbed_error_status_t mbed_get_last_error_info (mbed_error_ctx *error_info) { memcpy(error_info, &last_error_ctx, sizeof(mbed_error_ctx)); return MBED_SUCCESS; @@ -243,32 +274,32 @@ 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_LOG_DISABLED - status = mbed_log_reset(); +#ifndef MBED_CONF_ERROR_HIST_DISABLED + status = mbed_error_hist_reset(); #endif core_util_critical_section_exit(); return status; } -#ifndef MBED_CONF_ERROR_LOG_DISABLED +#ifndef MBED_CONF_ERROR_HIST_DISABLED //Retrieve the error context from error log at the specified index -mbed_error_status_t mbed_get_error_log_info (int index, mbed_error_ctx *error_info) +mbed_error_status_t mbed_get_error_hist_info (int index, mbed_error_ctx *error_info) { - return mbed_log_get_error(index, error_info); + return mbed_error_hist_get(index, error_info); } //Retrieve the error log count -int mbed_get_error_log_count(void) +int mbed_get_error_hist_count(void) { - return mbed_log_get_error_log_count(); + return mbed_error_hist_get_count(); } -mbed_error_status_t mbed_save_error_log(const char *path) +mbed_error_status_t mbed_save_error_hist(const char *path) { mbed_error_status_t ret = MBED_SUCCESS; mbed_error_ctx ctx = {0}; - int log_count = mbed_log_get_error_log_count(); + int log_count = mbed_error_hist_get_count(); FILE *error_log_file = NULL; //Ensure path is valid @@ -304,7 +335,7 @@ mbed_error_status_t mbed_save_error_log(const char *path) //Update with error log info while(--log_count >= 0) { - mbed_log_get_error(log_count, &ctx); + 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", log_count, @@ -323,6 +354,84 @@ 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 Entity: %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); +#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED + if(NULL != error_ctx->error_filename) { + //for string, we must pass address of a ptr which has the address of the string + uint32_t *file_name = (uint32_t *)&error_ctx->error_filename[0]; + mbed_error_printf("\nFile:%s", &file_name); + mbed_error_printf("+0x%x", 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 --"); +} + #endif diff --git a/platform/mbed_error.h b/platform/mbed_error.h index c97e0e566d..4d48c6e483 100644 --- a/platform/mbed_error.h +++ b/platform/mbed_error.h @@ -34,7 +34,7 @@ extern "C" { */ /** Define this macro to disable error logging, note that the first and last error capture will still be active by default. - * MBED_CONF_ERROR_LOG_DISABLED + * MBED_CONF_ERROR_HIST_DISABLED */ #ifndef MBED_CONF_MAX_ERROR_FILENAME_LEN @@ -805,10 +805,6 @@ typedef struct _mbed_error_ctx { * @param format C string that contains data stream to be printed. * Code snippets below show valid format. * - * @deprecated - * This function has been deprecated, please use one of MBED_WARNING/MBED_ERROR macros - * or one of mbed_error/mbed_warning functions. - * * @code * #error "That shouldn't have happened!" * @endcode @@ -846,8 +842,6 @@ typedef struct _mbed_error_ctx { * */ -MBED_DEPRECATED_SINCE("mbed-os-5.9", "This function has been deprecated, please use one of MBED_WARNING/MBED_ERROR macros or one of mbed_warning/mbed_error functions" ) - void error(const char* format, ...); /** @@ -932,21 +926,21 @@ mbed_error_status_t mbed_warning(mbed_error_status_t error_status, const char *e * @return mbed_error_status_t code logged for the first error or MBED_SUCCESS if no errors are logged. * */ -mbed_error_status_t get_first_error(void); +mbed_error_status_t mbed_get_first_error(void); /** * Returns the most recent system error reported. * @return mbed_error_status_t code logged for the last error or MBED_SUCCESS if no errors are logged. * */ -mbed_error_status_t get_last_error(void); +mbed_error_status_t mbed_get_last_error(void); /** * Returns the number of system errors reported after boot. * @return int Number of errors reported. * */ -int get_error_count(void); +int mbed_get_error_count(void); /** * Call this function to set a fatal system error and halt the system. This function will log the fatal error with the context info and prints the error report. @@ -998,7 +992,7 @@ mbed_error_status_t mbed_set_error_hook(mbed_error_hook_t custom_error_hook); * MBED_ERROR_INVALID_ARGUMENT in case of invalid index * */ -mbed_error_status_t mbed_get_first_error_log_info(mbed_error_ctx *error_info); +mbed_error_status_t mbed_get_first_error_info(mbed_error_ctx *error_info); /** * Reads the last error context information logged. @@ -1007,7 +1001,7 @@ mbed_error_status_t mbed_get_first_error_log_info(mbed_error_ctx *error_info); * MBED_ERROR_INVALID_ARGUMENT in case of invalid index * */ -mbed_error_status_t mbed_get_last_error_log_info(mbed_error_ctx *error_info); +mbed_error_status_t mbed_get_last_error_info(mbed_error_ctx *error_info); /** * Clears all the last error, error count and all entries in the error log. @@ -1031,7 +1025,7 @@ mbed_error_status_t mbed_make_error(mbed_error_type_t error_type, mbed_module_ty * @return Current number of entries in the error log. * */ -int mbed_get_error_log_count(void); +int mbed_get_error_hist_count(void); /** * Reads the error context information for a specific error log specified by the index. @@ -1044,7 +1038,7 @@ int mbed_get_error_log_count(void); * MBED_ERROR_INVALID_ARGUMENT in case of invalid index * */ -mbed_error_status_t mbed_get_error_log_info(int index, mbed_error_ctx *error_info); +mbed_error_status_t mbed_get_error_hist_info(int index, mbed_error_ctx *error_info); /** * Saves the error log information to a file @@ -1057,7 +1051,7 @@ mbed_error_status_t mbed_get_error_log_info(int index, mbed_error_ctx *error_inf * @note Filesystem support is required in order for this function to work. * */ -mbed_error_status_t mbed_save_error_log(const char *path); +mbed_error_status_t mbed_save_error_hist(const char *path); #ifdef __cplusplus } diff --git a/platform/mbed_error_log.c b/platform/mbed_error_hist.c similarity index 71% rename from platform/mbed_error_log.c rename to platform/mbed_error_hist.c index 3a144169a5..3420a78553 100644 --- a/platform/mbed_error_log.c +++ b/platform/mbed_error_hist.c @@ -21,13 +21,13 @@ #include "platform/mbed_critical.h" #include "platform/mbed_interface.h" -#ifndef MBED_CONF_ERROR_LOG_DISABLED -#include "platform/mbed_error_log.h" +#ifndef MBED_CONF_ERROR_HIST_DISABLED +#include "platform/mbed_error_hist.h" -static mbed_error_ctx mbed_error_ctx_log[MBED_CONF_ERROR_LOG_SIZE] = {0}; +static mbed_error_ctx mbed_error_ctx_log[MBED_CONF_ERROR_HIST_SIZE] = {0}; static int error_log_count = -1; -mbed_error_status_t mbed_log_put_error(mbed_error_ctx *error_ctx) +mbed_error_status_t mbed_error_hist_put(mbed_error_ctx *error_ctx) { //Return error if error_ctx is NULL if(NULL == error_ctx) { @@ -36,58 +36,58 @@ mbed_error_status_t mbed_log_put_error(mbed_error_ctx *error_ctx) core_util_critical_section_enter(); error_log_count++; - memcpy(&mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_LOG_SIZE], error_ctx, sizeof(mbed_error_ctx) ); + memcpy(&mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_HIST_SIZE], error_ctx, sizeof(mbed_error_ctx) ); core_util_critical_section_exit(); return MBED_SUCCESS; } -mbed_error_status_t mbed_log_get_error(int index, 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_LOG_SIZE) { + if(index >= MBED_CONF_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_LOG_SIZE) { - index = (error_log_count + index + 1) % MBED_CONF_ERROR_LOG_SIZE; + if(error_log_count >= MBED_CONF_ERROR_HIST_SIZE) { + index = (error_log_count + index + 1) % MBED_CONF_ERROR_HIST_SIZE; } core_util_critical_section_exit(); - memcpy(error_ctx, &mbed_error_ctx_log[index % MBED_CONF_ERROR_LOG_SIZE], sizeof(mbed_error_ctx) ); + memcpy(error_ctx, &mbed_error_ctx_log[index % MBED_CONF_ERROR_HIST_SIZE], sizeof(mbed_error_ctx) ); return MBED_SUCCESS; } -mbed_error_ctx *mbed_log_get_entry(void) +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_LOG_SIZE]; + mbed_error_ctx *ctx = &mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_HIST_SIZE]; core_util_critical_section_exit(); return ctx; } -mbed_error_status_t mbed_log_get_last_error(mbed_error_ctx *error_ctx) +mbed_error_status_t mbed_error_hist_get_last_error(mbed_error_ctx *error_ctx) { 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_LOG_SIZE], sizeof(mbed_error_ctx) ); + memcpy(error_ctx, &mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_HIST_SIZE], sizeof(mbed_error_ctx) ); core_util_critical_section_exit(); return MBED_SUCCESS; } -int mbed_log_get_error_log_count() +int mbed_error_hist_get_count() { - return (error_log_count >= MBED_CONF_ERROR_LOG_SIZE? MBED_CONF_ERROR_LOG_SIZE:error_log_count+1); + return (error_log_count >= MBED_CONF_ERROR_HIST_SIZE? MBED_CONF_ERROR_HIST_SIZE:error_log_count+1); } -mbed_error_status_t mbed_log_reset() +mbed_error_status_t mbed_error_hist_reset() { core_util_critical_section_enter(); error_log_count = -1; diff --git a/platform/mbed_error_log.h b/platform/mbed_error_hist.h similarity index 56% rename from platform/mbed_error_log.h rename to platform/mbed_error_hist.h index 0acd945261..b4380237e4 100644 --- a/platform/mbed_error_log.h +++ b/platform/mbed_error_hist.h @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef MBED_ERROR_LOG_H -#define MBED_ERROR_LOG_H +#ifndef MBED_ERROR_HIST_H +#define MBED_ERROR_HIST_H -#ifndef MBED_CONF_ERROR_LOG_SIZE - #define MBED_CONF_ERROR_LOG_SIZE 4 +#ifndef MBED_CONF_ERROR_HIST_SIZE + #define MBED_CONF_ERROR_HIST_SIZE 4 #else - #if MBED_CONF_ERROR_LOG_SIZE == 0 - #define MBED_CONF_ERROR_LOG_SIZE 1 + #if MBED_CONF_ERROR_HIST_SIZE == 0 + #define MBED_CONF_ERROR_HIST_SIZE 1 #endif #endif @@ -28,16 +28,16 @@ extern "C" { #endif /* - * Puts/Adds an error entry into the error list + * Puts/Adds an error entry into the error history list * * @param error_ctx pointer to the mbed_error_ctx struct with the error context * @return 0 or MBED_SUCCESS on success. - * ERROR_WRITE_FAILED if writing to file failed - * ERROR_INVALID_ARGUMENT if path is not valid + * MBED_ERROR_WRITE_FAILED if writing to file failed + * MBED_ERROR_INVALID_ARGUMENT if path is not valid * * */ -mbed_error_status_t mbed_log_put_error(mbed_error_ctx *error_ctx); +mbed_error_status_t mbed_error_hist_put(mbed_error_ctx *error_ctx); /* * Reads the error entry from the error list with the specified index @@ -45,12 +45,12 @@ mbed_error_status_t mbed_log_put_error(mbed_error_ctx *error_ctx); * @param index Index of the error context to be retrieved. It starts from 0 and 0 is the oldest. * @param error_ctx pointer to the mbed_error_ctx struct where the error context will be filled, this should be allocated by the caller * @return 0 or MBED_SUCCESS on success. - * ERROR_WRITE_FAILED if writing to file failed - * ERROR_INVALID_ARGUMENT if path is not valid + * MBED_ERROR_WRITE_FAILED if writing to file failed + * MBED_ERROR_INVALID_ARGUMENT if path is not valid * * */ -mbed_error_status_t mbed_log_get_error(int index, mbed_error_ctx *error_ctx); +mbed_error_status_t mbed_error_hist_get(int index, mbed_error_ctx *error_ctx); /* * Gets a reference to the next error entry in the error log where in the error ctx can be filled in. @@ -60,52 +60,52 @@ mbed_error_status_t mbed_log_get_error(int index, mbed_error_ctx *error_ctx); * * */ -mbed_error_ctx *mbed_log_get_entry(void); +mbed_error_ctx *mbed_error_hist_get_entry(void); /* - * Reads the last(latest) error entry from the error list + * Reads the last(latest) error entry from the error history * * @param error_ctx pointer to the mbed_error_ctx struct where the error context will be filled, this should be allocated by the caller * @return 0 or MBED_SUCCESS on success. - * ERROR_WRITE_FAILED if writing to file failed - * ERROR_INVALID_ARGUMENT if path is not valid + * MBED_ERROR_WRITE_FAILED if writing to file failed + * MBED_ERROR_INVALID_ARGUMENT if path is not valid * * */ -mbed_error_status_t mbed_log_get_last_error(mbed_error_ctx *error_ctx); +mbed_error_status_t mbed_error_hist_get_last_error(mbed_error_ctx *error_ctx); /* - * Returns the number of error entries in the error list + * Returns the number of error entries in the error history list * - * @return Number of entries in the list + * @return Number of entries in the history list * * */ -int mbed_log_get_error_log_count(void); +int mbed_error_hist_get_count(void); /* - * Resets the error log by resetting the number of errors to 0 and clears all previous errors in the log + * Resets the error log by resetting the number of errors to 0 and clears all previous errors in the history list * * @return 0 or MBED_SUCCESS on success. - * ERROR_WRITE_FAILED if writing to file failed - * ERROR_INVALID_ARGUMENT if path is not valid + * MBED_ERROR_WRITE_FAILED if writing to file failed + * MBED_ERROR_INVALID_ARGUMENT if path is not valid * * */ -mbed_error_status_t mbed_log_reset(void); +mbed_error_status_t mbed_error_hist_reset(void); /* * Saves the error log information to a file * * @param path path to the file in the filesystem * @return 0 or MBED_SUCCESS on success. - * ERROR_WRITE_FAILED if writing to file failed - * ERROR_INVALID_ARGUMENT if path is not valid + * MBED_ERROR_WRITE_FAILED if writing to file failed + * MBED_ERROR_INVALID_ARGUMENT if path is not valid * * @note Filesystem support is required in order for this function to work. * */ -mbed_error_status_t mbed_save_error_log(const char *path); +mbed_error_status_t mbed_save_error_hist(const char *path); #ifdef __cplusplus } diff --git a/platform/mbed_error_report.c b/platform/mbed_error_report.c deleted file mode 100644 index 08ace8b1dc..0000000000 --- a/platform/mbed_error_report.c +++ /dev/null @@ -1,278 +0,0 @@ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include -#include -#include "hal/serial_api.h" -#include "hal/itm_api.h" -#include "platform/mbed_error.h" -#include "platform/mbed_error_report.h" - -#ifdef DEVICE_SERIAL -extern int stdio_uart_inited; -extern serial_t stdio_uart; -#endif - -//Helper macro to get the current SP -#define GET_CURRENT_SP(sp) \ - { \ - /*If in Handler mode we are always using MSP*/ \ - if( __get_IPSR() != 0U ) { \ - sp = __get_MSP(); \ - } else { \ - /*Look into CONTROL.SPSEL value*/ \ - if ((__get_CONTROL() & 2U) == 0U) { \ - sp = __get_MSP();/*Read MSP*/ \ - } else { \ - sp = __get_PSP();/*Read PSP*/ \ - } \ - } \ - } - -/* 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)]; - } -} - -/* Converts a uint32 to dec char string */ -static void value_to_dec_str(uint32_t value, char *dec_str) -{ - char dec_char_map[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; - int i = 0; - - //Return without converting if hex_str is not provided - if(dec_str == NULL) return; - - while(value > 0) { - dec_str[i++] = dec_char_map[value % 10]; - value = value / 10; - } -} - -void mbed_error_init(void) -{ -#if DEVICE_SERIAL && (MBED_CONF_ERROR_REPORT_INTERFACE==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 && (MBED_CONF_ERROR_REPORT_INTERFACE==DEVICE_ITM) - /*Initialize ITM interfaces*/ - mbed_itm_init(); -#endif -} - -void mbed_error_putc(char ch) -{ -#if DEVICE_SERIAL && (MBED_CONF_ERROR_REPORT_INTERFACE==DEVICE_SERIAL) - serial_putc(&stdio_uart, ch); -#endif - -#if DEVICE_ITM && (MBED_CONF_ERROR_REPORT_INTERFACE==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. -*/ -void mbed_error_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 - mbed_error_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--) { - mbed_error_putc(num_str[idx]); - } - } - else if(fmtstr[i]=='d') { - memset(num_str, '0', sizeof(num_str)); - //print the number in dec format - value_to_dec_str(values[vidx++],num_str); - idx=5;//Start from 5 as we dont have big decimal numbers - while(num_str[idx--]=='0' && idx > 0);//Dont print zeros at front - for(idx++;idx>=0; idx--) { - mbed_error_putc(num_str[idx]); - } - } - else if(fmtstr[i]=='s') { - //print the string - str = (char *)((uint32_t)values[vidx++]); - while(*str != '\0') { - mbed_error_putc(*str); - str++; - } - str = NULL; - } else { - //Do not handle any other % formatting and keep going - } - } else { - //handle carriage returns - if (fmtstr[i] == '\n') { - mbed_error_putc('\r'); - } - mbed_error_putc(fmtstr[i]); - } - i++; - } -#endif -} - -#ifdef MBED_CONF_RTOS_PRESENT -/* Prints thread info from a list */ -void print_threads_info(osRtxThread_t *threads) -{ - while(threads != NULL) { - print_thread( threads ); - threads = threads->thread_next; - } -} - -/* Prints info of a thread(using osRtxThread_t struct)*/ -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; - mbed_error_print("\nState: 0x%x Entry: 0x%x Stack Size: 0x%x Mem: 0x%x SP: 0x%x", data); -} -#endif - -/* Prints the error information */ -void mbed_report_error(mbed_error_ctx *error_ctx, char *error_msg) -{ - uint32_t error_vals[3] = {0}; - error_vals[0] = error_ctx->error_status; - error_vals[1] = MBED_GET_ERROR_CODE(error_ctx->error_status); - error_vals[2] = MBED_GET_ERROR_MODULE(error_ctx->error_status); - - mbed_error_print("\n\n++ MbedOS Error Info ++\nError Status: 0x%x Code: %d Entity: %d\nError Message: ", error_vals); - - //Report error info based on error code, some errors require different - //error_vals[1] contains the error code - if(error_vals[1] == MBED_ERROR_CODE_HARDFAULT_EXCEPTION || - error_vals[1] == MBED_ERROR_CODE_MEMMANAGE_EXCEPTION || - error_vals[1] == MBED_ERROR_CODE_BUSFAULT_EXCEPTION || - error_vals[1] == MBED_ERROR_CODE_USAGEFAULT_EXCEPTION ) { - mbed_error_print(error_msg, NULL); - mbed_error_print("\nLocation: 0x%x\n", (uint32_t *)&error_ctx->error_value); - } else { - switch (error_vals[1]) { - //These are errors reported by kernel handled from mbed_rtx_handlers - case MBED_ERROR_CODE_RTOS_EVENT: - mbed_error_print("Kernel Error: 0x%x, ", (uint32_t *)&error_ctx->error_value); - break; - - case MBED_ERROR_CODE_RTOS_THREAD_EVENT: - mbed_error_print("Thread: 0x%x, ", (uint32_t *)&error_ctx->error_value); - break; - - case MBED_ERROR_CODE_RTOS_MUTEX_EVENT: - mbed_error_print("Mutex: 0x%x, ", (uint32_t *)&error_ctx->error_value); - break; - - case MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT: - mbed_error_print("Semaphore: 0x%x, ", (uint32_t *)&error_ctx->error_value); - break; - - case MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT: - mbed_error_print("MemoryPool: 0x%x, ", (uint32_t *)&error_ctx->error_value); - break; - - case MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT: - mbed_error_print("EventFlags: 0x%x, ", (uint32_t *)&error_ctx->error_value); - break; - - case MBED_ERROR_CODE_RTOS_TIMER_EVENT: - mbed_error_print("Timer: 0x%x, ", (uint32_t *)&error_ctx->error_value); - break; - - case MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT: - mbed_error_print("MessageQueue: 0x%x, ", (uint32_t *)&error_ctx->error_value); - break; - - default: - //Nothing to do here, just print the error info down - break; - } - mbed_error_print(error_msg, NULL); - mbed_error_print("\nLocation: 0x%x", (uint32_t *)&error_ctx->error_address); -#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED - if(NULL != error_ctx->error_filename) { - //for string, we must pass address of a ptr which has the address of the string - uint32_t *file_name = (uint32_t *)&error_ctx->error_filename[0]; - mbed_error_print("\nFile:%s", &file_name); - mbed_error_print("+0x%x", (uint32_t *)&error_ctx->error_line_number); - } -#endif - -#ifdef MBED_CONF_RTOS_PRESENT - //Capture thread info - osRtxThread_t *current_thread = osRtxInfo.thread.run.curr; - error_ctx->thread_id = (uint32_t)current_thread; - error_ctx->thread_entry_address = (uint32_t)current_thread->thread_addr; - error_ctx->thread_stack_size = current_thread->stack_size; - error_ctx->thread_stack_mem = (uint32_t)current_thread->stack_mem; -#ifdef TARGET_CORTEX_M - GET_CURRENT_SP(error_ctx->thread_current_sp); - - //Take advantage of the fact that the thread info in context struct is consecutively placed - mbed_error_print("\nError Value: 0x%x\nCurrent Thread: Id: 0x%x Entry: 0x%x StackSize: 0x%x StackMem: 0x%x SP: 0x%x ", - (uint32_t *)&error_ctx->error_value); -#else - //For Cortex-A targets we dont have support to capture the current SP - //Take advantage of the fact that the thread info in context struct is consecutively placed - mbed_error_print("\nError Value: 0x%x\nCurrent Thread: Id: 0x%x Entry: 0x%x StackSize: 0x%x StackMem: 0x%x ", - (uint32_t *)&error_ctx->error_value); -#endif //TARGET_CORTEX_M - -#endif //MBED_CONF_RTOS_PRESENT - } - - mbed_error_print("\n-- MbedOS Error Info --", NULL); -} diff --git a/platform/mbed_error_report.h b/platform/mbed_error_report.h deleted file mode 100644 index 6102450088..0000000000 --- a/platform/mbed_error_report.h +++ /dev/null @@ -1,82 +0,0 @@ - -/** \addtogroup platform */ -/** @{*/ -/* mbed Microcontroller Library - * Copyright (c) 2006-2013 ARM Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef MBED_ERROR_REPORT_H -#define MBED_ERROR_REPORT_H - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef MBED_CONF_ERROR_REPORT_INTERFACE -#define MBED_CONF_ERROR_REPORT_INTERFACE DEVICE_SERIAL -#endif - -#ifdef MBED_CONF_RTOS_PRESENT -#include "rtx_os.h" - -/* Prints thread info from a list - * @param threads Pointer to the list of osRtxThread_t structs for which the thread info will be printed - * - */ -void print_threads_info(osRtxThread_t *threads); - -/* Prints info of a thread(using osRtxThread_t struct) - * @param thread Pointer to the osRtxThread_t struct for which the thread info will be printed - * - */ -void print_thread(osRtxThread_t *thread); -#endif - -/* Routine to report the error - * @param error_ctx This is the error context struct containing the error info - * @param error_msg Error message to be used when reporting the error - * - */ -void mbed_report_error(mbed_error_ctx *error_ctx, char *error_msg); - -/* 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. - * @param fmstr format string to be used, currently we support %x(hex) %d(decimal) %s(string) formatters only. - * @param values This should be a pointer to array of values used for printing corresponding to the format specifiers(%x,%d,%s)) mentioned - * - */ -void mbed_error_print(char *fmtstr, uint32_t *values); - -/* Initializes the data structures and interfaces for printing the error output - * - */ -void mbed_error_init(void); - -/* Routine which putc into serial/itm interface - * @param ch character to print - * - */ -void mbed_error_putc(char ch); - -#ifdef __cplusplus -} -#endif - -#endif - -/** @}*/ diff --git a/rtos/TARGET_CORTEX/TARGET_CORTEX_M/mbed_rtx_fault_handler.c b/rtos/TARGET_CORTEX/TARGET_CORTEX_M/mbed_rtx_fault_handler.c index 06f54e2a21..89482ad908 100644 --- a/rtos/TARGET_CORTEX/TARGET_CORTEX_M/mbed_rtx_fault_handler.c +++ b/rtos/TARGET_CORTEX/TARGET_CORTEX_M/mbed_rtx_fault_handler.c @@ -17,69 +17,193 @@ #include "rtx_os.h" #include "device.h" #include "platform/mbed_error.h" -#include "platform/mbed_error_report.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) { mbed_error_status_t faultStatus = MBED_SUCCESS; - mbed_error_print("\n++ MbedOS Fault Handler ++\n\nFaultType: ",NULL); + fault_print("\n++ MbedOS Fault Handler ++\n\nFaultType: ",NULL); switch( fault_type ) { case HARD_FAULT_EXCEPTION: - mbed_error_print("HardFault",NULL); + fault_print("HardFault",NULL); faultStatus = MBED_ERROR_HARDFAULT_EXCEPTION; break; case MEMMANAGE_FAULT_EXCEPTION: - mbed_error_print("MemManageFault",NULL); + fault_print("MemManageFault",NULL); faultStatus = MBED_ERROR_MEMMANAGE_EXCEPTION; break; case BUS_FAULT_EXCEPTION: - mbed_error_print("BusFault",NULL); + fault_print("BusFault",NULL); faultStatus = MBED_ERROR_BUSFAULT_EXCEPTION; break; case USAGE_FAULT_EXCEPTION: - mbed_error_print("UsageFault",NULL); + fault_print("UsageFault",NULL); faultStatus = MBED_ERROR_USAGEFAULT_EXCEPTION; break; default: - mbed_error_print("Unknown Fault",NULL); + fault_print("Unknown Fault",NULL); faultStatus = MBED_ERROR_UNKNOWN; break; } - mbed_error_print("\n\nContext:",NULL); + fault_print("\n\nContext:",NULL); print_context_info(); - mbed_error_print("\n\nThreads Info:\nCurrent:",NULL); + fault_print("\n\nThreads Info:\nCurrent:",NULL); print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.curr); - mbed_error_print("\nNext:",NULL); + fault_print("\nNext:",NULL); print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.next); - mbed_error_print("\nWait:",NULL); + fault_print("\nWait:",NULL); osRtxThread_t *threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.wait_list; print_threads_info(threads); - mbed_error_print("\nDelay:",NULL); + fault_print("\nDelay:",NULL); threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.delay_list; print_threads_info(threads); - mbed_error_print("\nIdle:",NULL); + fault_print("\nIdle:",NULL); threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.idle; print_threads_info(threads); - mbed_error_print("\n\n-- MbedOS Fault Handler --\n\n",NULL); + fault_print("\n\n-- MbedOS Fault Handler --\n\n",NULL); //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 excaption, halting system.", mbed_fault_context.PC_reg, NULL, 0 ); @@ -93,7 +217,7 @@ __NO_RETURN void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_conte void print_context_info(void) { //Context Regs - mbed_error_print("\nR0 : %x" + fault_print("\nR0 : %x" "\nR1 : %x" "\nR2 : %x" "\nR3 : %x" @@ -114,7 +238,7 @@ void print_context_info(void) "\nMSP : %x", (uint32_t *)&mbed_fault_context); //Capture CPUID to get core/cpu info - mbed_error_print("\nCPUID: %x",(uint32_t *)&SCB->CPUID); + fault_print("\nCPUID: %x",(uint32_t *)&SCB->CPUID); #if !defined(TARGET_M0) && !defined(TARGET_M0P) //Capture fault information registers to infer the cause of exception @@ -128,7 +252,7 @@ void print_context_info(void) FSR[4] = SCB->DFSR; FSR[5] = SCB->AFSR; FSR[6] = SCB->SHCSR; - mbed_error_print("\nHFSR : %x" + fault_print("\nHFSR : %x" "\nMMFSR: %x" "\nBFSR : %x" "\nUFSR : %x" @@ -138,33 +262,33 @@ void print_context_info(void) //Print MMFAR only if its valid as indicated by MMFSR if(FSR[1] & 0x80) { - mbed_error_print("\nMMFAR: %x",(uint32_t *)&SCB->MMFAR); + fault_print("\nMMFAR: %x",(uint32_t *)&SCB->MMFAR); } //Print BFAR only if its valid as indicated by BFSR if(FSR[2] & 0x80) { - mbed_error_print("\nBFAR : %x",(uint32_t *)&SCB->BFAR); + fault_print("\nBFAR : %x",(uint32_t *)&SCB->BFAR); } #endif //Print Mode if(mbed_fault_context.EXC_RETURN & 0x8) { - mbed_error_print("\nMode : Thread", NULL); + fault_print("\nMode : Thread", NULL); //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) { - mbed_error_print("\nPriv : User", NULL); + fault_print("\nPriv : User", NULL); } else { - mbed_error_print("\nPriv : Privileged", NULL); + fault_print("\nPriv : Privileged", NULL); } } else { - mbed_error_print("\nMode : Handler", NULL); - mbed_error_print("\nPriv : Privileged", NULL); + fault_print("\nMode : Handler", NULL); + fault_print("\nPriv : Privileged", NULL); } //Print Return Stack if(mbed_fault_context.EXC_RETURN & 0x4) { - mbed_error_print("\nStack: PSP", NULL); + fault_print("\nStack: PSP", NULL); } else { - mbed_error_print("\nStack: MSP", NULL); + fault_print("\nStack: MSP", NULL); } }