mbed_error.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /* mbed Microcontroller Library
  2. * Copyright (c) 2006-2013 ARM Limited
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <stdlib.h>
  17. #include <stdarg.h>
  18. #include <string.h>
  19. #include "device.h"
  20. #include "platform/mbed_critical.h"
  21. #include "platform/mbed_error.h"
  22. #include "platform/mbed_error_hist.h"
  23. #include "platform/mbed_interface.h"
  24. #ifdef MBED_CONF_RTOS_PRESENT
  25. #include "rtx_os.h"
  26. #endif
  27. #if DEVICE_STDIO_MESSAGES
  28. #include <stdio.h>
  29. #endif
  30. //Helper macro to get the current SP
  31. #define GET_CURRENT_SP(sp) \
  32. { \
  33. /*If in Handler mode we are always using MSP*/ \
  34. if ( __get_IPSR() != 0U ) { \
  35. sp = __get_MSP(); \
  36. } else { \
  37. /*Look into CONTROL.SPSEL value*/ \
  38. if ((__get_CONTROL() & 2U) == 0U) { \
  39. sp = __get_MSP();/*Read MSP*/ \
  40. } else { \
  41. sp = __get_PSP();/*Read PSP*/ \
  42. } \
  43. } \
  44. }
  45. #ifndef NDEBUG
  46. #define ERROR_REPORT(ctx, error_msg) print_error_report(ctx, error_msg)
  47. #else
  48. #define ERROR_REPORT(ctx, error_msg) ((void) 0)
  49. #endif
  50. static uint8_t error_in_progress = 0;
  51. static int error_count = 0;
  52. static mbed_error_ctx first_error_ctx = {0};
  53. static mbed_error_ctx last_error_ctx = {0};
  54. static mbed_error_hook_t error_hook = NULL;
  55. static void print_error_report(mbed_error_ctx *ctx, const char *);
  56. 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);
  57. //Helper function to halt the system
  58. static void mbed_halt_system(void)
  59. {
  60. //If not in ISR context exit, otherwise spin on WFI
  61. if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
  62. for (;;) {
  63. __WFI();
  64. }
  65. } else {
  66. //exit eventually calls mbed_die
  67. exit(1);
  68. }
  69. }
  70. WEAK void error(const char *format, ...)
  71. {
  72. // Prevent recursion if error is called again
  73. if (error_in_progress) {
  74. return;
  75. }
  76. //Call handle_error/print_error_report permanently setting error_in_progress flag
  77. handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0, MBED_CALLER_ADDR());
  78. ERROR_REPORT(&last_error_ctx, "Fatal Run-time error");
  79. error_in_progress = 1;
  80. #ifndef NDEBUG
  81. va_list arg;
  82. va_start(arg, format);
  83. mbed_error_vfprintf(format, arg);
  84. va_end(arg);
  85. #endif
  86. exit(1);
  87. }
  88. //Set an error status with the error handling system
  89. 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)
  90. {
  91. mbed_error_ctx current_error_ctx;
  92. //Error status should always be < 0
  93. if (error_status >= 0) {
  94. //This is a weird situation, someone called mbed_error with invalid error code.
  95. //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
  96. error_status = MBED_ERROR_INVALID_ARGUMENT;
  97. }
  98. //Prevent corruption by holding out other callers
  99. //and we also need this until we remove the "error" call completely
  100. while (error_in_progress == 1);
  101. //Use critsect here, as we don't want inadvertant modification of this global variable
  102. core_util_critical_section_enter();
  103. error_in_progress = 1;
  104. core_util_critical_section_exit();
  105. //Increment error count
  106. error_count++;
  107. //Clear the context capturing buffer
  108. memset(&current_error_ctx, sizeof(mbed_error_ctx), 0);
  109. //Capture error information
  110. current_error_ctx.error_status = error_status;
  111. current_error_ctx.error_address = (uint32_t)caller;
  112. current_error_ctx.error_value = error_value;
  113. #ifdef MBED_CONF_RTOS_PRESENT
  114. //Capture thread info
  115. osRtxThread_t *current_thread = osRtxInfo.thread.run.curr;
  116. current_error_ctx.thread_id = (uint32_t)current_thread;
  117. current_error_ctx.thread_entry_address = (uint32_t)current_thread->thread_addr;
  118. current_error_ctx.thread_stack_size = current_thread->stack_size;
  119. current_error_ctx.thread_stack_mem = (uint32_t)current_thread->stack_mem;
  120. #ifdef TARGET_CORTEX_M
  121. GET_CURRENT_SP(current_error_ctx.thread_current_sp);
  122. #endif //TARGET_CORTEX_M
  123. #endif //MBED_CONF_RTOS_PRESENT
  124. #if MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED
  125. //Capture filename/linenumber if provided
  126. //Index for tracking error_filename
  127. memset(&current_error_ctx.error_filename, 0, MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN);
  128. strncpy(current_error_ctx.error_filename, filename, MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN);
  129. current_error_ctx.error_line_number = line_number;
  130. #endif
  131. //Capture the fist system error and store it
  132. if (error_count == 1) { //first error
  133. memcpy(&first_error_ctx, &current_error_ctx, sizeof(mbed_error_ctx));
  134. }
  135. //copy this error to last error
  136. memcpy(&last_error_ctx, &current_error_ctx, sizeof(mbed_error_ctx));
  137. #if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
  138. //Log the error with error log
  139. mbed_error_hist_put(&current_error_ctx);
  140. #endif
  141. //Call the error hook if available
  142. if (error_hook != NULL) {
  143. error_hook(&last_error_ctx);
  144. }
  145. error_in_progress = 0;
  146. return MBED_SUCCESS;
  147. }
  148. //Return the first error
  149. mbed_error_status_t mbed_get_first_error(void)
  150. {
  151. //return the first error recorded
  152. return first_error_ctx.error_status;
  153. }
  154. //Return the last error
  155. mbed_error_status_t mbed_get_last_error(void)
  156. {
  157. //return the last error recorded
  158. return last_error_ctx.error_status;
  159. }
  160. //Gets the current error count
  161. int mbed_get_error_count(void)
  162. {
  163. //return the current error count
  164. return error_count;
  165. }
  166. //Sets a fatal error
  167. 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)
  168. {
  169. return handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR());
  170. }
  171. //Sets a fatal error, this function is marked WEAK to be able to override this for some tests
  172. 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)
  173. {
  174. //set the error reported and then halt the system
  175. if (MBED_SUCCESS != handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR())) {
  176. return MBED_ERROR_FAILED_OPERATION;
  177. }
  178. //On fatal errors print the error context/report
  179. ERROR_REPORT(&last_error_ctx, error_msg);
  180. mbed_halt_system();
  181. return MBED_ERROR_FAILED_OPERATION;
  182. }
  183. //Register an application defined callback with error handling
  184. mbed_error_status_t mbed_set_error_hook(mbed_error_hook_t error_hook_in)
  185. {
  186. //register the new hook/callback
  187. if (error_hook_in != NULL) {
  188. error_hook = error_hook_in;
  189. return MBED_SUCCESS;
  190. }
  191. return MBED_ERROR_INVALID_ARGUMENT;
  192. }
  193. //Retrieve the first error context from error log
  194. mbed_error_status_t mbed_get_first_error_info(mbed_error_ctx *error_info)
  195. {
  196. memcpy(error_info, &first_error_ctx, sizeof(first_error_ctx));
  197. return MBED_SUCCESS;
  198. }
  199. //Retrieve the last error context from error log
  200. mbed_error_status_t mbed_get_last_error_info(mbed_error_ctx *error_info)
  201. {
  202. memcpy(error_info, &last_error_ctx, sizeof(mbed_error_ctx));
  203. return MBED_SUCCESS;
  204. }
  205. //Makes an mbed_error_status_t value
  206. mbed_error_status_t mbed_make_error(mbed_error_type_t error_type, mbed_module_type_t entity, mbed_error_code_t error_code)
  207. {
  208. switch (error_type) {
  209. case MBED_ERROR_TYPE_POSIX:
  210. if (error_code >= MBED_POSIX_ERROR_BASE && error_code <= MBED_SYSTEM_ERROR_BASE) {
  211. return -error_code;
  212. }
  213. break;
  214. case MBED_ERROR_TYPE_SYSTEM:
  215. if (error_code >= MBED_SYSTEM_ERROR_BASE && error_code <= MBED_CUSTOM_ERROR_BASE) {
  216. return MAKE_MBED_ERROR(MBED_ERROR_TYPE_SYSTEM, entity, error_code);
  217. }
  218. break;
  219. case MBED_ERROR_TYPE_CUSTOM:
  220. if (error_code >= MBED_CUSTOM_ERROR_BASE) {
  221. return MAKE_MBED_ERROR(MBED_ERROR_TYPE_CUSTOM, entity, error_code);
  222. }
  223. break;
  224. default:
  225. break;
  226. }
  227. //If we are passed incorrect values return a generic system error
  228. return MAKE_MBED_ERROR(MBED_ERROR_TYPE_SYSTEM, MBED_MODULE_UNKNOWN, MBED_ERROR_CODE_UNKNOWN);
  229. }
  230. /**
  231. * Clears all the last error, error count and all entries in the error log.
  232. * @return 0 or MBED_SUCCESS on success.
  233. *
  234. */
  235. mbed_error_status_t mbed_clear_all_errors(void)
  236. {
  237. mbed_error_status_t status = MBED_SUCCESS;
  238. //Make sure we dont multiple clients resetting
  239. core_util_critical_section_enter();
  240. //Clear the error and context capturing buffer
  241. memset(&last_error_ctx, sizeof(mbed_error_ctx), 0);
  242. //reset error count to 0
  243. error_count = 0;
  244. #if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
  245. status = mbed_error_hist_reset();
  246. #endif
  247. core_util_critical_section_exit();
  248. return status;
  249. }
  250. #if MBED_CONF_PLATFORM_ERROR_ALL_THREADS_INFO && defined(MBED_CONF_RTOS_PRESENT)
  251. /* Prints info of a thread(using osRtxThread_t struct)*/
  252. static void print_thread(osRtxThread_t *thread)
  253. {
  254. 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);
  255. }
  256. /* Prints thread info from a list */
  257. static void print_threads_info(osRtxThread_t *threads)
  258. {
  259. while (threads != NULL) {
  260. print_thread(threads);
  261. threads = threads->thread_next;
  262. }
  263. }
  264. #endif
  265. #ifndef NDEBUG
  266. static void print_error_report(mbed_error_ctx *ctx, const char *error_msg)
  267. {
  268. uint32_t error_code = MBED_GET_ERROR_CODE(ctx->error_status);
  269. uint32_t error_module = MBED_GET_ERROR_MODULE(ctx->error_status);
  270. 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);
  271. switch (error_code) {
  272. //These are errors reported by kernel handled from mbed_rtx_handlers
  273. case MBED_ERROR_CODE_RTOS_EVENT:
  274. mbed_error_printf("Kernel Error: 0x%X, ", ctx->error_value);
  275. break;
  276. case MBED_ERROR_CODE_RTOS_THREAD_EVENT:
  277. mbed_error_printf("Thread: 0x%X, ", ctx->error_value);
  278. break;
  279. case MBED_ERROR_CODE_RTOS_MUTEX_EVENT:
  280. mbed_error_printf("Mutex: 0x%X, ", ctx->error_value);
  281. break;
  282. case MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT:
  283. mbed_error_printf("Semaphore: 0x%X, ", ctx->error_value);
  284. break;
  285. case MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT:
  286. mbed_error_printf("MemoryPool: 0x%X, ", ctx->error_value);
  287. break;
  288. case MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT:
  289. mbed_error_printf("EventFlags: 0x%X, ", ctx->error_value);
  290. break;
  291. case MBED_ERROR_CODE_RTOS_TIMER_EVENT:
  292. mbed_error_printf("Timer: 0x%X, ", ctx->error_value);
  293. break;
  294. case MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT:
  295. mbed_error_printf("MessageQueue: 0x%X, ", ctx->error_value);
  296. break;
  297. default:
  298. //Nothing to do here, just print the error info down
  299. break;
  300. }
  301. mbed_error_printf(error_msg);
  302. mbed_error_printf("\nLocation: 0x%X", ctx->error_address);
  303. #if MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED && !defined(NDEBUG)
  304. if ((NULL != ctx->error_filename[0]) && (ctx->error_line_number != 0)) {
  305. //for string, we must pass address of a ptr which has the address of the string
  306. mbed_error_printf("\nFile:%s+%d", ctx->error_filename, ctx->error_line_number);
  307. }
  308. #endif
  309. mbed_error_printf("\nError Value: 0x%X", ctx->error_value);
  310. #ifdef TARGET_CORTEX_M
  311. mbed_error_printf("\nCurrent Thread: Id: 0x%X Entry: 0x%X StackSize: 0x%X StackMem: 0x%X SP: 0x%X ",
  312. ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem, ctx->thread_current_sp);
  313. #else
  314. //For Cortex-A targets we dont have support to capture the current SP
  315. mbed_error_printf("\nCurrent Thread: Id: 0x%X Entry: 0x%X StackSize: 0x%X StackMem: 0x%X ",
  316. ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem);
  317. #endif //TARGET_CORTEX_M
  318. #if MBED_CONF_PLATFORM_ERROR_ALL_THREADS_INFO && defined(MBED_CONF_RTOS_PRESENT)
  319. mbed_error_printf("\nNext:");
  320. print_thread(osRtxInfo.thread.run.next);
  321. mbed_error_printf("\nWait:");
  322. osRtxThread_t *threads = (osRtxThread_t *)&osRtxInfo.thread.wait_list;
  323. print_threads_info(threads);
  324. mbed_error_printf("\nDelay:");
  325. threads = (osRtxThread_t *)&osRtxInfo.thread.delay_list;
  326. print_threads_info(threads);
  327. mbed_error_printf("\nIdle:");
  328. threads = (osRtxThread_t *)&osRtxInfo.thread.idle;
  329. print_threads_info(threads);
  330. #endif
  331. mbed_error_printf("\n-- MbedOS Error Info --\n");
  332. }
  333. #endif //ifndef NDEBUG
  334. #if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
  335. //Retrieve the error context from error log at the specified index
  336. mbed_error_status_t mbed_get_error_hist_info(int index, mbed_error_ctx *error_info)
  337. {
  338. return mbed_error_hist_get(index, error_info);
  339. }
  340. //Retrieve the error log count
  341. int mbed_get_error_hist_count(void)
  342. {
  343. return mbed_error_hist_get_count();
  344. }
  345. mbed_error_status_t mbed_save_error_hist(const char *path)
  346. {
  347. mbed_error_status_t ret = MBED_SUCCESS;
  348. mbed_error_ctx ctx = {0};
  349. int log_count = mbed_error_hist_get_count();
  350. FILE *error_log_file = NULL;
  351. //Ensure path is valid
  352. if (path == NULL) {
  353. ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INVALID_ARGUMENT);
  354. goto exit;
  355. }
  356. //Open the file for saving the error log info
  357. if ((error_log_file = fopen(path, "w")) == NULL) {
  358. ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OPEN_FAILED);
  359. goto exit;
  360. }
  361. //First store the first and last errors
  362. if (fprintf(error_log_file, "\nFirst Error: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n",
  363. (unsigned int)first_error_ctx.error_status,
  364. (unsigned int)first_error_ctx.thread_id,
  365. (unsigned int)first_error_ctx.error_address,
  366. (unsigned int)first_error_ctx.error_value) <= 0) {
  367. ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED);
  368. goto exit;
  369. }
  370. if (fprintf(error_log_file, "\nLast Error: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n",
  371. (unsigned int)last_error_ctx.error_status,
  372. (unsigned int)last_error_ctx.thread_id,
  373. (unsigned int)last_error_ctx.error_address,
  374. (unsigned int)last_error_ctx.error_value) <= 0) {
  375. ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED);
  376. goto exit;
  377. }
  378. //Update with error log info
  379. while (--log_count >= 0) {
  380. mbed_error_hist_get(log_count, &ctx);
  381. //first line of file will be error log count
  382. if (fprintf(error_log_file, "\n%d: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n",
  383. log_count,
  384. (unsigned int)ctx.error_status,
  385. (unsigned int)ctx.thread_id,
  386. (unsigned int)ctx.error_address,
  387. (unsigned int)ctx.error_value) <= 0) {
  388. ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED);
  389. goto exit;
  390. }
  391. }
  392. exit:
  393. fclose(error_log_file);
  394. return ret;
  395. }
  396. #endif