Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-dev by
mbed_error.c
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2013 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 #include <stdlib.h> 00017 #include <stdarg.h> 00018 #include <string.h> 00019 #include "device.h" 00020 #include "platform/mbed_critical.h" 00021 #include "platform/mbed_error.h" 00022 #include "platform/mbed_error_hist.h" 00023 #include "platform/mbed_interface.h" 00024 #ifdef MBED_CONF_RTOS_PRESENT 00025 #include "rtx_os.h" 00026 #endif 00027 00028 #if DEVICE_STDIO_MESSAGES 00029 #include <stdio.h> 00030 #endif 00031 00032 //Helper macro to get the current SP 00033 #define GET_CURRENT_SP(sp) \ 00034 { \ 00035 /*If in Handler mode we are always using MSP*/ \ 00036 if( __get_IPSR() != 0U ) { \ 00037 sp = __get_MSP(); \ 00038 } else { \ 00039 /*Look into CONTROL.SPSEL value*/ \ 00040 if ((__get_CONTROL() & 2U) == 0U) { \ 00041 sp = __get_MSP();/*Read MSP*/ \ 00042 } else { \ 00043 sp = __get_PSP();/*Read PSP*/ \ 00044 } \ 00045 } \ 00046 } 00047 00048 00049 static uint8_t error_in_progress = 0; 00050 static int error_count = 0; 00051 static mbed_error_ctx first_error_ctx = {0}; 00052 static mbed_error_ctx last_error_ctx = {0}; 00053 static mbed_error_hook_t error_hook = NULL; 00054 static void print_error_report(mbed_error_ctx *ctx, const char *); 00055 static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsigned int error_value, const char *filename, int line_number); 00056 00057 //Helper function to halt the system 00058 static void mbed_halt_system(void) 00059 { 00060 //If not in ISR context exit, otherwise spin on WFI 00061 if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) { 00062 for(;;) { 00063 __WFI(); 00064 } 00065 } else { 00066 //exit eventually calls mbed_die 00067 exit(1); 00068 } 00069 } 00070 00071 WEAK void error(const char* format, ...) { 00072 00073 // Prevent recursion if error is called again 00074 if (error_in_progress) { 00075 return; 00076 } 00077 00078 //Call handle_error/print_error_report permanently setting error_in_progress flag 00079 handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0); 00080 print_error_report(&last_error_ctx, "Fatal Run-time error"); 00081 error_in_progress = 1; 00082 00083 #ifndef NDEBUG 00084 va_list arg; 00085 va_start(arg, format); 00086 mbed_error_vfprintf(format, arg); 00087 va_end(arg); 00088 #endif 00089 exit(1); 00090 } 00091 00092 //Set an error status with the error handling system 00093 static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsigned int error_value, const char *filename, int line_number) 00094 { 00095 mbed_error_ctx current_error_ctx; 00096 00097 //Error status should always be < 0 00098 if(error_status >= 0) { 00099 //This is a weird situation, someone called mbed_error with invalid error code. 00100 //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 00101 error_status = MBED_ERROR_INVALID_ARGUMENT; 00102 } 00103 00104 //Prevent corruption by holding out other callers 00105 //and we also need this until we remove the "error" call completely 00106 while (error_in_progress == 1); 00107 00108 //Use critsect here, as we don't want inadvertant modification of this global variable 00109 core_util_critical_section_enter(); 00110 error_in_progress = 1; 00111 core_util_critical_section_exit(); 00112 00113 //Increment error count 00114 error_count++; 00115 00116 //Clear the context capturing buffer 00117 memset(¤t_error_ctx, sizeof(mbed_error_ctx), 0); 00118 //Capture error information 00119 current_error_ctx.error_status = error_status; 00120 current_error_ctx.error_address = (uint32_t)MBED_CALLER_ADDR(); 00121 current_error_ctx.error_value = error_value; 00122 #ifdef MBED_CONF_RTOS_PRESENT 00123 //Capture thread info 00124 osRtxThread_t *current_thread = osRtxInfo.thread.run.curr; 00125 current_error_ctx.thread_id = (uint32_t)current_thread; 00126 current_error_ctx.thread_entry_address = (uint32_t)current_thread->thread_addr; 00127 current_error_ctx.thread_stack_size = current_thread->stack_size; 00128 current_error_ctx.thread_stack_mem = (uint32_t)current_thread->stack_mem; 00129 #ifdef TARGET_CORTEX_M 00130 GET_CURRENT_SP(current_error_ctx.thread_current_sp); 00131 #endif //TARGET_CORTEX_M 00132 00133 #endif //MBED_CONF_RTOS_PRESENT 00134 00135 #ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED 00136 //Capture filename/linenumber if provided 00137 //Index for tracking error_filename 00138 memset(¤t_error_ctx.error_filename, 0, MBED_CONF_MAX_ERROR_FILENAME_LEN); 00139 strncpy(current_error_ctx.error_filename, filename, MBED_CONF_MAX_ERROR_FILENAME_LEN); 00140 current_error_ctx.error_line_number = line_number; 00141 #endif 00142 00143 //Capture the fist system error and store it 00144 if(error_count == 1) { //first error 00145 memcpy(&first_error_ctx, ¤t_error_ctx, sizeof(mbed_error_ctx)); 00146 } 00147 00148 //copy this error to last error 00149 memcpy(&last_error_ctx, ¤t_error_ctx, sizeof(mbed_error_ctx)); 00150 00151 #ifndef MBED_CONF_ERROR_HIST_DISABLED 00152 //Log the error with error log 00153 mbed_error_hist_put(¤t_error_ctx); 00154 #endif 00155 00156 //Call the error hook if available 00157 if(error_hook != NULL) { 00158 error_hook(&last_error_ctx); 00159 } 00160 00161 error_in_progress = 0; 00162 00163 return MBED_SUCCESS; 00164 } 00165 00166 //Return the first error 00167 mbed_error_status_t mbed_get_first_error(void) 00168 { 00169 //return the first error recorded 00170 return first_error_ctx.error_status; 00171 } 00172 00173 //Return the last error 00174 mbed_error_status_t mbed_get_last_error(void) 00175 { 00176 //return the last error recorded 00177 return last_error_ctx.error_status; 00178 } 00179 00180 //Gets the current error count 00181 int mbed_get_error_count(void) 00182 { 00183 //return the current error count 00184 return error_count; 00185 } 00186 00187 //Sets a fatal error 00188 mbed_error_status_t mbed_warning(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number) 00189 { 00190 return handle_error(error_status, error_value, filename, line_number); 00191 } 00192 00193 //Sets a fatal error 00194 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) 00195 { 00196 //set the error reported and then halt the system 00197 if( MBED_SUCCESS != handle_error(error_status, error_value, filename, line_number) ) 00198 return MBED_ERROR_FAILED_OPERATION; 00199 00200 //On fatal errors print the error context/report 00201 print_error_report(&last_error_ctx, error_msg); 00202 mbed_halt_system(); 00203 00204 return MBED_ERROR_FAILED_OPERATION; 00205 } 00206 00207 //Register an application defined callback with error handling 00208 mbed_error_status_t mbed_set_error_hook(mbed_error_hook_t error_hook_in) 00209 { 00210 //register the new hook/callback 00211 if( error_hook_in != NULL ) { 00212 error_hook = error_hook_in; 00213 return MBED_SUCCESS; 00214 } 00215 00216 return MBED_ERROR_INVALID_ARGUMENT; 00217 } 00218 00219 //Retrieve the first error context from error log 00220 mbed_error_status_t mbed_get_first_error_info (mbed_error_ctx *error_info) 00221 { 00222 memcpy(error_info, &first_error_ctx, sizeof(first_error_ctx)); 00223 return MBED_SUCCESS; 00224 } 00225 00226 //Retrieve the last error context from error log 00227 mbed_error_status_t mbed_get_last_error_info (mbed_error_ctx *error_info) 00228 { 00229 memcpy(error_info, &last_error_ctx, sizeof(mbed_error_ctx)); 00230 return MBED_SUCCESS; 00231 } 00232 00233 //Makes an mbed_error_status_t value 00234 mbed_error_status_t mbed_make_error(mbed_error_type_t error_type, mbed_module_type_t entity, mbed_error_code_t error_code) 00235 { 00236 switch(error_type) 00237 { 00238 case MBED_ERROR_TYPE_POSIX: 00239 if(error_code >= MBED_POSIX_ERROR_BASE && error_code <= MBED_SYSTEM_ERROR_BASE) 00240 return -error_code; 00241 break; 00242 00243 case MBED_ERROR_TYPE_SYSTEM: 00244 if(error_code >= MBED_SYSTEM_ERROR_BASE && error_code <= MBED_CUSTOM_ERROR_BASE) 00245 return MAKE_MBED_ERROR(MBED_ERROR_TYPE_SYSTEM, entity, error_code); 00246 break; 00247 00248 case MBED_ERROR_TYPE_CUSTOM: 00249 if(error_code >= MBED_CUSTOM_ERROR_BASE) 00250 return MAKE_MBED_ERROR(MBED_ERROR_TYPE_CUSTOM, entity, error_code); 00251 break; 00252 00253 default: 00254 break; 00255 } 00256 00257 //If we are passed incorrect values return a generic system error 00258 return MAKE_MBED_ERROR(MBED_ERROR_TYPE_SYSTEM, MBED_MODULE_UNKNOWN, MBED_ERROR_CODE_UNKNOWN); 00259 } 00260 00261 /** 00262 * Clears all the last error, error count and all entries in the error log. 00263 * @return 0 or MBED_SUCCESS on success. 00264 * 00265 */ 00266 mbed_error_status_t mbed_clear_all_errors(void) 00267 { 00268 mbed_error_status_t status = MBED_SUCCESS; 00269 00270 //Make sure we dont multiple clients resetting 00271 core_util_critical_section_enter(); 00272 //Clear the error and context capturing buffer 00273 memset(&last_error_ctx, sizeof(mbed_error_ctx), 0); 00274 //reset error count to 0 00275 error_count = 0; 00276 #ifndef MBED_CONF_ERROR_HIST_DISABLED 00277 status = mbed_error_hist_reset(); 00278 #endif 00279 core_util_critical_section_exit(); 00280 00281 return status; 00282 } 00283 00284 #ifndef MBED_CONF_ERROR_HIST_DISABLED 00285 //Retrieve the error context from error log at the specified index 00286 mbed_error_status_t mbed_get_error_hist_info (int index, mbed_error_ctx *error_info) 00287 { 00288 return mbed_error_hist_get(index, error_info); 00289 } 00290 00291 //Retrieve the error log count 00292 int mbed_get_error_hist_count(void) 00293 { 00294 return mbed_error_hist_get_count(); 00295 } 00296 00297 mbed_error_status_t mbed_save_error_hist(const char *path) 00298 { 00299 mbed_error_status_t ret = MBED_SUCCESS; 00300 mbed_error_ctx ctx = {0}; 00301 int log_count = mbed_error_hist_get_count(); 00302 FILE *error_log_file = NULL; 00303 00304 //Ensure path is valid 00305 if(path==NULL) { 00306 ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INVALID_ARGUMENT); 00307 goto exit; 00308 } 00309 00310 //Open the file for saving the error log info 00311 if((error_log_file = fopen( path, "w" ) ) == NULL){ 00312 ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OPEN_FAILED); 00313 goto exit; 00314 } 00315 00316 //First store the first and last errors 00317 if(fprintf(error_log_file, "\nFirst Error: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n", 00318 (unsigned int)first_error_ctx.error_status, 00319 (unsigned int)first_error_ctx.thread_id, 00320 (unsigned int)first_error_ctx.error_address, 00321 (unsigned int)first_error_ctx.error_value) <= 0) { 00322 ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED); 00323 goto exit; 00324 } 00325 00326 if(fprintf(error_log_file, "\nLast Error: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n", 00327 (unsigned int)last_error_ctx.error_status, 00328 (unsigned int)last_error_ctx.thread_id, 00329 (unsigned int)last_error_ctx.error_address, 00330 (unsigned int)last_error_ctx.error_value) <= 0) { 00331 ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED); 00332 goto exit; 00333 } 00334 00335 //Update with error log info 00336 while(--log_count >= 0) { 00337 mbed_error_hist_get(log_count, &ctx); 00338 //first line of file will be error log count 00339 if(fprintf(error_log_file, "\n%d: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n", 00340 log_count, 00341 (unsigned int)ctx.error_status, 00342 (unsigned int)ctx.thread_id, 00343 (unsigned int)ctx.error_address, 00344 (unsigned int)ctx.error_value) <= 0) { 00345 ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED); 00346 goto exit; 00347 } 00348 } 00349 00350 exit: 00351 fclose(error_log_file); 00352 00353 return ret; 00354 } 00355 00356 static void print_error_report(mbed_error_ctx *ctx, const char *error_msg) 00357 { 00358 uint32_t error_code = MBED_GET_ERROR_CODE(ctx->error_status); 00359 uint32_t error_module = MBED_GET_ERROR_MODULE(ctx->error_status); 00360 00361 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); 00362 00363 //Report error info based on error code, some errors require different 00364 //error_vals[1] contains the error code 00365 if(error_code == MBED_ERROR_CODE_HARDFAULT_EXCEPTION || 00366 error_code == MBED_ERROR_CODE_MEMMANAGE_EXCEPTION || 00367 error_code == MBED_ERROR_CODE_BUSFAULT_EXCEPTION || 00368 error_code == MBED_ERROR_CODE_USAGEFAULT_EXCEPTION ) { 00369 mbed_error_printf(error_msg); 00370 mbed_error_printf("\nLocation: 0x%x\n", ctx->error_value); 00371 } else { 00372 switch (error_code) { 00373 //These are errors reported by kernel handled from mbed_rtx_handlers 00374 case MBED_ERROR_CODE_RTOS_EVENT: 00375 mbed_error_printf("Kernel Error: 0x%x, ", ctx->error_value); 00376 break; 00377 00378 case MBED_ERROR_CODE_RTOS_THREAD_EVENT: 00379 mbed_error_printf("Thread: 0x%x, ", ctx->error_value); 00380 break; 00381 00382 case MBED_ERROR_CODE_RTOS_MUTEX_EVENT: 00383 mbed_error_printf("Mutex: 0x%x, ", ctx->error_value); 00384 break; 00385 00386 case MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT: 00387 mbed_error_printf("Semaphore: 0x%x, ", ctx->error_value); 00388 break; 00389 00390 case MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT: 00391 mbed_error_printf("MemoryPool: 0x%x, ", ctx->error_value); 00392 break; 00393 00394 case MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT: 00395 mbed_error_printf("EventFlags: 0x%x, ", ctx->error_value); 00396 break; 00397 00398 case MBED_ERROR_CODE_RTOS_TIMER_EVENT: 00399 mbed_error_printf("Timer: 0x%x, ", ctx->error_value); 00400 break; 00401 00402 case MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT: 00403 mbed_error_printf("MessageQueue: 0x%x, ", ctx->error_value); 00404 break; 00405 00406 default: 00407 //Nothing to do here, just print the error info down 00408 break; 00409 } 00410 mbed_error_printf(error_msg, NULL); 00411 mbed_error_printf("\nLocation: 0x%x", ctx->error_address); 00412 #if defined(MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED) && !defined(NDEBUG) 00413 if(NULL != ctx->error_filename) { 00414 //for string, we must pass address of a ptr which has the address of the string 00415 mbed_error_printf("\nFile:%s+%d", ctx->error_filename, ctx->error_line_number); 00416 } 00417 #endif 00418 00419 #ifdef TARGET_CORTEX_M 00420 mbed_error_printf("\nError Value: 0x%x\nCurrent Thread: Id: 0x%x Entry: 0x%x StackSize: 0x%x StackMem: 0x%x SP: 0x%x ", 00421 ctx->error_value, ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem, ctx->thread_current_sp); 00422 #else 00423 //For Cortex-A targets we dont have support to capture the current SP 00424 mbed_error_printf("\nError Value: 0x%x\nCurrent Thread: Id: 0x%x Entry: 0x%x StackSize: 0x%x StackMem: 0x%x ", 00425 ctx->error_value, ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem); 00426 #endif //TARGET_CORTEX_M 00427 } 00428 00429 mbed_error_printf("\n-- MbedOS Error Info --\n"); 00430 } 00431 00432 00433 #endif 00434
Generated on Tue Jul 12 2022 12:59:33 by
1.7.2
