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.
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 #ifndef NDEBUG 00049 #define ERROR_REPORT(ctx, error_msg) print_error_report(ctx, error_msg) 00050 #else 00051 #define ERROR_REPORT(ctx, error_msg) ((void) 0) 00052 #endif 00053 00054 static uint8_t error_in_progress = 0; 00055 static int error_count = 0; 00056 static mbed_error_ctx first_error_ctx = {0}; 00057 static mbed_error_ctx last_error_ctx = {0}; 00058 static mbed_error_hook_t error_hook = NULL; 00059 static void print_error_report(mbed_error_ctx *ctx, const char *); 00060 static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsigned int error_value, const char *filename, int line_number, void *caller); 00061 00062 //Helper function to halt the system 00063 static void mbed_halt_system(void) 00064 { 00065 //If not in ISR context exit, otherwise spin on WFI 00066 if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) { 00067 for (;;) { 00068 __WFI(); 00069 } 00070 } else { 00071 //exit eventually calls mbed_die 00072 exit(1); 00073 } 00074 } 00075 00076 WEAK void error(const char *format, ...) 00077 { 00078 00079 // Prevent recursion if error is called again 00080 if (error_in_progress) { 00081 return; 00082 } 00083 00084 //Call handle_error/print_error_report permanently setting error_in_progress flag 00085 handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0, MBED_CALLER_ADDR()); 00086 ERROR_REPORT(&last_error_ctx, "Fatal Run-time error"); 00087 error_in_progress = 1; 00088 00089 #ifndef NDEBUG 00090 va_list arg; 00091 va_start(arg, format); 00092 mbed_error_vfprintf(format, arg); 00093 va_end(arg); 00094 #endif 00095 exit(1); 00096 } 00097 00098 //Set an error status with the error handling system 00099 static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsigned int error_value, const char *filename, int line_number, void *caller) 00100 { 00101 mbed_error_ctx current_error_ctx; 00102 00103 //Error status should always be < 0 00104 if (error_status >= 0) { 00105 //This is a weird situation, someone called mbed_error with invalid error code. 00106 //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 00107 error_status = MBED_ERROR_INVALID_ARGUMENT; 00108 } 00109 00110 //Prevent corruption by holding out other callers 00111 //and we also need this until we remove the "error" call completely 00112 while (error_in_progress == 1); 00113 00114 //Use critsect here, as we don't want inadvertant modification of this global variable 00115 core_util_critical_section_enter(); 00116 error_in_progress = 1; 00117 core_util_critical_section_exit(); 00118 00119 //Increment error count 00120 error_count++; 00121 00122 //Clear the context capturing buffer 00123 memset(¤t_error_ctx, 0, sizeof(mbed_error_ctx)); 00124 //Capture error information 00125 current_error_ctx.error_status = error_status; 00126 current_error_ctx.error_address = (uint32_t)caller; 00127 current_error_ctx.error_value = error_value; 00128 #ifdef MBED_CONF_RTOS_PRESENT 00129 //Capture thread info 00130 osRtxThread_t *current_thread = osRtxInfo.thread.run.curr; 00131 current_error_ctx.thread_id = (uint32_t)current_thread; 00132 current_error_ctx.thread_entry_address = (uint32_t)current_thread->thread_addr; 00133 current_error_ctx.thread_stack_size = current_thread->stack_size; 00134 current_error_ctx.thread_stack_mem = (uint32_t)current_thread->stack_mem; 00135 #ifdef TARGET_CORTEX_M 00136 GET_CURRENT_SP(current_error_ctx.thread_current_sp); 00137 #endif //TARGET_CORTEX_M 00138 00139 #endif //MBED_CONF_RTOS_PRESENT 00140 00141 #if MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED 00142 //Capture filename/linenumber if provided 00143 //Index for tracking error_filename 00144 memset(¤t_error_ctx.error_filename, 0, MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN); 00145 strncpy(current_error_ctx.error_filename, filename, MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN); 00146 current_error_ctx.error_line_number = line_number; 00147 #endif 00148 00149 //Capture the fist system error and store it 00150 if (error_count == 1) { //first error 00151 memcpy(&first_error_ctx, ¤t_error_ctx, sizeof(mbed_error_ctx)); 00152 } 00153 00154 //copy this error to last error 00155 memcpy(&last_error_ctx, ¤t_error_ctx, sizeof(mbed_error_ctx)); 00156 00157 #if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED 00158 //Log the error with error log 00159 mbed_error_hist_put(¤t_error_ctx); 00160 #endif 00161 00162 //Call the error hook if available 00163 if (error_hook != NULL) { 00164 error_hook(&last_error_ctx); 00165 } 00166 00167 error_in_progress = 0; 00168 00169 return MBED_SUCCESS; 00170 } 00171 00172 //Return the first error 00173 mbed_error_status_t mbed_get_first_error(void) 00174 { 00175 //return the first error recorded 00176 return first_error_ctx.error_status; 00177 } 00178 00179 //Return the last error 00180 mbed_error_status_t mbed_get_last_error(void) 00181 { 00182 //return the last error recorded 00183 return last_error_ctx.error_status; 00184 } 00185 00186 //Gets the current error count 00187 int mbed_get_error_count(void) 00188 { 00189 //return the current error count 00190 return error_count; 00191 } 00192 00193 //Sets a fatal error 00194 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) 00195 { 00196 return handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR()); 00197 } 00198 00199 //Sets a fatal error, this function is marked WEAK to be able to override this for some tests 00200 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) 00201 { 00202 //set the error reported and then halt the system 00203 if (MBED_SUCCESS != handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR())) { 00204 return MBED_ERROR_FAILED_OPERATION; 00205 } 00206 00207 //On fatal errors print the error context/report 00208 ERROR_REPORT(&last_error_ctx, error_msg); 00209 mbed_halt_system(); 00210 00211 return MBED_ERROR_FAILED_OPERATION; 00212 } 00213 00214 //Register an application defined callback with error handling 00215 mbed_error_status_t mbed_set_error_hook(mbed_error_hook_t error_hook_in) 00216 { 00217 //register the new hook/callback 00218 if (error_hook_in != NULL) { 00219 error_hook = error_hook_in; 00220 return MBED_SUCCESS; 00221 } 00222 00223 return MBED_ERROR_INVALID_ARGUMENT; 00224 } 00225 00226 //Retrieve the first error context from error log 00227 mbed_error_status_t mbed_get_first_error_info(mbed_error_ctx *error_info) 00228 { 00229 memcpy(error_info, &first_error_ctx, sizeof(first_error_ctx)); 00230 return MBED_SUCCESS; 00231 } 00232 00233 //Retrieve the last error context from error log 00234 mbed_error_status_t mbed_get_last_error_info(mbed_error_ctx *error_info) 00235 { 00236 memcpy(error_info, &last_error_ctx, sizeof(mbed_error_ctx)); 00237 return MBED_SUCCESS; 00238 } 00239 00240 //Makes an mbed_error_status_t value 00241 mbed_error_status_t mbed_make_error(mbed_error_type_t error_type, mbed_module_type_t entity, mbed_error_code_t error_code) 00242 { 00243 switch (error_type) { 00244 case MBED_ERROR_TYPE_POSIX: 00245 if (error_code >= MBED_POSIX_ERROR_BASE && error_code <= MBED_SYSTEM_ERROR_BASE) { 00246 return -error_code; 00247 } 00248 break; 00249 00250 case MBED_ERROR_TYPE_SYSTEM: 00251 if (error_code >= MBED_SYSTEM_ERROR_BASE && error_code <= MBED_CUSTOM_ERROR_BASE) { 00252 return MAKE_MBED_ERROR(MBED_ERROR_TYPE_SYSTEM, entity, error_code); 00253 } 00254 break; 00255 00256 case MBED_ERROR_TYPE_CUSTOM: 00257 if (error_code >= MBED_CUSTOM_ERROR_BASE) { 00258 return MAKE_MBED_ERROR(MBED_ERROR_TYPE_CUSTOM, entity, error_code); 00259 } 00260 break; 00261 00262 default: 00263 break; 00264 } 00265 00266 //If we are passed incorrect values return a generic system error 00267 return MAKE_MBED_ERROR(MBED_ERROR_TYPE_SYSTEM, MBED_MODULE_UNKNOWN, MBED_ERROR_CODE_UNKNOWN); 00268 } 00269 00270 /** 00271 * Clears all the last error, error count and all entries in the error log. 00272 * @return 0 or MBED_SUCCESS on success. 00273 * 00274 */ 00275 mbed_error_status_t mbed_clear_all_errors(void) 00276 { 00277 mbed_error_status_t status = MBED_SUCCESS; 00278 00279 //Make sure we dont multiple clients resetting 00280 core_util_critical_section_enter(); 00281 //Clear the error and context capturing buffer 00282 memset(&last_error_ctx, 0, sizeof(mbed_error_ctx)); 00283 //reset error count to 0 00284 error_count = 0; 00285 #if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED 00286 status = mbed_error_hist_reset(); 00287 #endif 00288 core_util_critical_section_exit(); 00289 00290 return status; 00291 } 00292 00293 #if MBED_CONF_PLATFORM_ERROR_ALL_THREADS_INFO && defined(MBED_CONF_RTOS_PRESENT) 00294 /* Prints info of a thread(using osRtxThread_t struct)*/ 00295 static void print_thread(osRtxThread_t *thread) 00296 { 00297 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); 00298 } 00299 00300 /* Prints thread info from a list */ 00301 static void print_threads_info(osRtxThread_t *threads) 00302 { 00303 while (threads != NULL) { 00304 print_thread(threads); 00305 threads = threads->thread_next; 00306 } 00307 } 00308 #endif 00309 00310 #ifndef NDEBUG 00311 static void print_error_report(mbed_error_ctx *ctx, const char *error_msg) 00312 { 00313 uint32_t error_code = MBED_GET_ERROR_CODE(ctx->error_status); 00314 uint32_t error_module = MBED_GET_ERROR_MODULE(ctx->error_status); 00315 00316 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); 00317 00318 switch (error_code) { 00319 //These are errors reported by kernel handled from mbed_rtx_handlers 00320 case MBED_ERROR_CODE_RTOS_EVENT: 00321 mbed_error_printf("Kernel Error: 0x%X, ", ctx->error_value); 00322 break; 00323 00324 case MBED_ERROR_CODE_RTOS_THREAD_EVENT: 00325 mbed_error_printf("Thread: 0x%X, ", ctx->error_value); 00326 break; 00327 00328 case MBED_ERROR_CODE_RTOS_MUTEX_EVENT: 00329 mbed_error_printf("Mutex: 0x%X, ", ctx->error_value); 00330 break; 00331 00332 case MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT: 00333 mbed_error_printf("Semaphore: 0x%X, ", ctx->error_value); 00334 break; 00335 00336 case MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT: 00337 mbed_error_printf("MemoryPool: 0x%X, ", ctx->error_value); 00338 break; 00339 00340 case MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT: 00341 mbed_error_printf("EventFlags: 0x%X, ", ctx->error_value); 00342 break; 00343 00344 case MBED_ERROR_CODE_RTOS_TIMER_EVENT: 00345 mbed_error_printf("Timer: 0x%X, ", ctx->error_value); 00346 break; 00347 00348 case MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT: 00349 mbed_error_printf("MessageQueue: 0x%X, ", ctx->error_value); 00350 break; 00351 00352 default: 00353 //Nothing to do here, just print the error info down 00354 break; 00355 } 00356 mbed_error_printf(error_msg); 00357 mbed_error_printf("\nLocation: 0x%X", ctx->error_address); 00358 00359 #if MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED && !defined(NDEBUG) 00360 if ((NULL != ctx->error_filename[0]) && (ctx->error_line_number != 0)) { 00361 //for string, we must pass address of a ptr which has the address of the string 00362 mbed_error_printf("\nFile:%s+%d", ctx->error_filename, ctx->error_line_number); 00363 } 00364 #endif 00365 00366 mbed_error_printf("\nError Value: 0x%X", ctx->error_value); 00367 #ifdef TARGET_CORTEX_M 00368 mbed_error_printf("\nCurrent Thread: Id: 0x%X Entry: 0x%X StackSize: 0x%X StackMem: 0x%X SP: 0x%X ", 00369 ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem, ctx->thread_current_sp); 00370 #else 00371 //For Cortex-A targets we dont have support to capture the current SP 00372 mbed_error_printf("\nCurrent Thread: Id: 0x%X Entry: 0x%X StackSize: 0x%X StackMem: 0x%X ", 00373 ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem); 00374 #endif //TARGET_CORTEX_M 00375 00376 #if MBED_CONF_PLATFORM_ERROR_ALL_THREADS_INFO && defined(MBED_CONF_RTOS_PRESENT) 00377 mbed_error_printf("\nNext:"); 00378 print_thread(osRtxInfo.thread.run.next); 00379 00380 mbed_error_printf("\nWait:"); 00381 osRtxThread_t *threads = (osRtxThread_t *)&osRtxInfo.thread.wait_list; 00382 print_threads_info(threads); 00383 00384 mbed_error_printf("\nDelay:"); 00385 threads = (osRtxThread_t *)&osRtxInfo.thread.delay_list; 00386 print_threads_info(threads); 00387 00388 mbed_error_printf("\nIdle:"); 00389 threads = (osRtxThread_t *)&osRtxInfo.thread.idle; 00390 print_threads_info(threads); 00391 #endif 00392 mbed_error_printf(MBED_CONF_PLATFORM_ERROR_DECODE_HTTP_URL_STR, ctx->error_status); 00393 mbed_error_printf("\n-- MbedOS Error Info --\n"); 00394 } 00395 #endif //ifndef NDEBUG 00396 00397 #if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED 00398 //Retrieve the error context from error log at the specified index 00399 mbed_error_status_t mbed_get_error_hist_info(int index, mbed_error_ctx *error_info) 00400 { 00401 return mbed_error_hist_get(index, error_info); 00402 } 00403 00404 //Retrieve the error log count 00405 int mbed_get_error_hist_count(void) 00406 { 00407 return mbed_error_hist_get_count(); 00408 } 00409 00410 mbed_error_status_t mbed_save_error_hist(const char *path) 00411 { 00412 mbed_error_status_t ret = MBED_SUCCESS; 00413 mbed_error_ctx ctx = {0}; 00414 int log_count = mbed_error_hist_get_count(); 00415 FILE *error_log_file = NULL; 00416 00417 //Ensure path is valid 00418 if (path == NULL) { 00419 ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INVALID_ARGUMENT); 00420 goto exit; 00421 } 00422 00423 //Open the file for saving the error log info 00424 if ((error_log_file = fopen(path, "w")) == NULL) { 00425 ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OPEN_FAILED); 00426 goto exit; 00427 } 00428 00429 //First store the first and last errors 00430 if (fprintf(error_log_file, "\nFirst Error: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n", 00431 (unsigned int)first_error_ctx.error_status, 00432 (unsigned int)first_error_ctx.thread_id, 00433 (unsigned int)first_error_ctx.error_address, 00434 (unsigned int)first_error_ctx.error_value) <= 0) { 00435 ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED); 00436 goto exit; 00437 } 00438 00439 if (fprintf(error_log_file, "\nLast Error: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n", 00440 (unsigned int)last_error_ctx.error_status, 00441 (unsigned int)last_error_ctx.thread_id, 00442 (unsigned int)last_error_ctx.error_address, 00443 (unsigned int)last_error_ctx.error_value) <= 0) { 00444 ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED); 00445 goto exit; 00446 } 00447 00448 //Update with error log info 00449 while (--log_count >= 0) { 00450 mbed_error_hist_get(log_count, &ctx); 00451 //first line of file will be error log count 00452 if (fprintf(error_log_file, "\n%d: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n", 00453 log_count, 00454 (unsigned int)ctx.error_status, 00455 (unsigned int)ctx.thread_id, 00456 (unsigned int)ctx.error_address, 00457 (unsigned int)ctx.error_value) <= 0) { 00458 ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED); 00459 goto exit; 00460 } 00461 } 00462 00463 exit: 00464 fclose(error_log_file); 00465 00466 return ret; 00467 } 00468 #endif 00469
Generated on Tue Aug 9 2022 00:37:14 by
