mbed_alloc_wrappers.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. /* mbed Microcontroller Library
  2. * Copyright (c) 2006-2016 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 "platform/mbed_mem_trace.h"
  17. #include "platform/mbed_stats.h"
  18. #include "platform/mbed_toolchain.h"
  19. #include "platform/SingletonPtr.h"
  20. #include "platform/PlatformMutex.h"
  21. #include <stddef.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <stdlib.h>
  25. /* There are two memory tracers in mbed OS:
  26. - the first can be used to detect the maximum heap usage at runtime. It is
  27. activated by defining the MBED_HEAP_STATS_ENABLED macro.
  28. - the second can be used to trace each memory call by automatically invoking
  29. a callback on each memory operation (see hal/api/mbed_mem_trace.h). It is
  30. activated by defining the MBED_MEM_TRACING_ENABLED macro.
  31. Both tracers can be activated and deactivated in any combination. If both tracers
  32. are active, the second one (MBED_MEM_TRACING_ENABLED) will trace the first one's
  33. (MBED_HEAP_STATS_ENABLED) memory calls.*/
  34. /******************************************************************************/
  35. /* Implementation of the runtime max heap usage checker */
  36. /******************************************************************************/
  37. /* Size must be a multiple of 8 to keep alignment */
  38. typedef struct {
  39. uint32_t size;
  40. uint32_t pad;
  41. } alloc_info_t;
  42. #ifdef MBED_HEAP_STATS_ENABLED
  43. static SingletonPtr<PlatformMutex> malloc_stats_mutex;
  44. static mbed_stats_heap_t heap_stats = {0, 0, 0, 0, 0};
  45. #endif
  46. void mbed_stats_heap_get(mbed_stats_heap_t *stats)
  47. {
  48. #ifdef MBED_HEAP_STATS_ENABLED
  49. extern uint32_t mbed_heap_size;
  50. heap_stats.reserved_size = mbed_heap_size;
  51. malloc_stats_mutex->lock();
  52. memcpy(stats, &heap_stats, sizeof(mbed_stats_heap_t));
  53. malloc_stats_mutex->unlock();
  54. #else
  55. memset(stats, 0, sizeof(mbed_stats_heap_t));
  56. #endif
  57. }
  58. /******************************************************************************/
  59. /* GCC memory allocation wrappers */
  60. /******************************************************************************/
  61. #if defined(TOOLCHAIN_GCC)
  62. #ifdef FEATURE_UVISOR
  63. #include "uvisor-lib/uvisor-lib.h"
  64. #endif/* FEATURE_UVISOR */
  65. extern "C" {
  66. void *__real__malloc_r(struct _reent *r, size_t size);
  67. void *__real__memalign_r(struct _reent *r, size_t alignment, size_t bytes);
  68. void *__real__realloc_r(struct _reent *r, void *ptr, size_t size);
  69. void __real__free_r(struct _reent *r, void *ptr);
  70. void *__real__calloc_r(struct _reent *r, size_t nmemb, size_t size);
  71. void *malloc_wrapper(struct _reent *r, size_t size, void *caller);
  72. void free_wrapper(struct _reent *r, void *ptr, void *caller);
  73. }
  74. // TODO: memory tracing doesn't work with uVisor enabled.
  75. #if !defined(FEATURE_UVISOR)
  76. extern "C" void *__wrap__malloc_r(struct _reent *r, size_t size)
  77. {
  78. return malloc_wrapper(r, size, MBED_CALLER_ADDR());
  79. }
  80. extern "C" void *malloc_wrapper(struct _reent *r, size_t size, void *caller)
  81. {
  82. void *ptr = NULL;
  83. #ifdef MBED_MEM_TRACING_ENABLED
  84. mbed_mem_trace_lock();
  85. #endif
  86. #ifdef MBED_HEAP_STATS_ENABLED
  87. malloc_stats_mutex->lock();
  88. alloc_info_t *alloc_info = (alloc_info_t *)__real__malloc_r(r, size + sizeof(alloc_info_t));
  89. if (alloc_info != NULL) {
  90. alloc_info->size = size;
  91. ptr = (void *)(alloc_info + 1);
  92. heap_stats.current_size += size;
  93. heap_stats.total_size += size;
  94. heap_stats.alloc_cnt += 1;
  95. if (heap_stats.current_size > heap_stats.max_size) {
  96. heap_stats.max_size = heap_stats.current_size;
  97. }
  98. } else {
  99. heap_stats.alloc_fail_cnt += 1;
  100. }
  101. malloc_stats_mutex->unlock();
  102. #else // #ifdef MBED_HEAP_STATS_ENABLED
  103. ptr = __real__malloc_r(r, size);
  104. #endif // #ifdef MBED_HEAP_STATS_ENABLED
  105. #ifdef MBED_MEM_TRACING_ENABLED
  106. mbed_mem_trace_malloc(ptr, size, caller);
  107. mbed_mem_trace_unlock();
  108. #endif // #ifdef MBED_MEM_TRACING_ENABLED
  109. return ptr;
  110. }
  111. extern "C" void *__wrap__realloc_r(struct _reent *r, void *ptr, size_t size)
  112. {
  113. void *new_ptr = NULL;
  114. #ifdef MBED_MEM_TRACING_ENABLED
  115. mbed_mem_trace_lock();
  116. #endif
  117. #ifdef MBED_HEAP_STATS_ENABLED
  118. // Implement realloc_r with malloc and free.
  119. // The function realloc_r can't be used here directly since
  120. // it can call into __wrap__malloc_r (returns ptr + 4) or
  121. // resize memory directly (returns ptr + 0).
  122. // Note - no lock needed since malloc and free are thread safe
  123. // Get old size
  124. uint32_t old_size = 0;
  125. if (ptr != NULL) {
  126. alloc_info_t *alloc_info = ((alloc_info_t *)ptr) - 1;
  127. old_size = alloc_info->size;
  128. }
  129. // Allocate space
  130. if (size != 0) {
  131. new_ptr = malloc(size);
  132. }
  133. // If the new buffer has been allocated copy the data to it
  134. // and free the old buffer
  135. if (new_ptr != NULL) {
  136. uint32_t copy_size = (old_size < size) ? old_size : size;
  137. memcpy(new_ptr, (void *)ptr, copy_size);
  138. free(ptr);
  139. }
  140. #else // #ifdef MBED_HEAP_STATS_ENABLED
  141. new_ptr = __real__realloc_r(r, ptr, size);
  142. #endif // #ifdef MBED_HEAP_STATS_ENABLED
  143. #ifdef MBED_MEM_TRACING_ENABLED
  144. mbed_mem_trace_realloc(new_ptr, ptr, size, MBED_CALLER_ADDR());
  145. mbed_mem_trace_unlock();
  146. #endif // #ifdef MBED_MEM_TRACING_ENABLED
  147. return new_ptr;
  148. }
  149. extern "C" void __wrap__free_r(struct _reent *r, void *ptr)
  150. {
  151. free_wrapper(r, ptr, MBED_CALLER_ADDR());
  152. }
  153. extern "C" void free_wrapper(struct _reent *r, void *ptr, void *caller)
  154. {
  155. #ifdef MBED_MEM_TRACING_ENABLED
  156. mbed_mem_trace_lock();
  157. #endif
  158. #ifdef MBED_HEAP_STATS_ENABLED
  159. malloc_stats_mutex->lock();
  160. alloc_info_t *alloc_info = NULL;
  161. if (ptr != NULL) {
  162. alloc_info = ((alloc_info_t *)ptr) - 1;
  163. heap_stats.current_size -= alloc_info->size;
  164. heap_stats.alloc_cnt -= 1;
  165. }
  166. __real__free_r(r, (void *)alloc_info);
  167. malloc_stats_mutex->unlock();
  168. #else // #ifdef MBED_HEAP_STATS_ENABLED
  169. __real__free_r(r, ptr);
  170. #endif // #ifdef MBED_HEAP_STATS_ENABLED
  171. #ifdef MBED_MEM_TRACING_ENABLED
  172. mbed_mem_trace_free(ptr, caller);
  173. mbed_mem_trace_unlock();
  174. #endif // #ifdef MBED_MEM_TRACING_ENABLED
  175. }
  176. extern "C" void *__wrap__calloc_r(struct _reent *r, size_t nmemb, size_t size)
  177. {
  178. void *ptr = NULL;
  179. #ifdef MBED_MEM_TRACING_ENABLED
  180. mbed_mem_trace_lock();
  181. #endif
  182. #ifdef MBED_HEAP_STATS_ENABLED
  183. // Note - no lock needed since malloc is thread safe
  184. ptr = malloc(nmemb * size);
  185. if (ptr != NULL) {
  186. memset(ptr, 0, nmemb * size);
  187. }
  188. #else // #ifdef MBED_HEAP_STATS_ENABLED
  189. ptr = __real__calloc_r(r, nmemb, size);
  190. #endif // #ifdef MBED_HEAP_STATS_ENABLED
  191. #ifdef MBED_MEM_TRACING_ENABLED
  192. mbed_mem_trace_calloc(ptr, nmemb, size, MBED_CALLER_ADDR());
  193. mbed_mem_trace_unlock();
  194. #endif // #ifdef MBED_MEM_TRACING_ENABLED
  195. return ptr;
  196. }
  197. extern "C" void *__wrap__memalign_r(struct _reent *r, size_t alignment, size_t bytes)
  198. {
  199. return __real__memalign_r(r, alignment, bytes);
  200. }
  201. #endif // if !defined(FEATURE_UVISOR)
  202. /******************************************************************************/
  203. /* ARMCC / IAR memory allocation wrappers */
  204. /******************************************************************************/
  205. #elif defined(TOOLCHAIN_ARM) || defined(__ICCARM__)
  206. #if defined(TOOLCHAIN_ARM)
  207. #define SUPER_MALLOC $Super$$malloc
  208. #define SUB_MALLOC $Sub$$malloc
  209. #define SUPER_REALLOC $Super$$realloc
  210. #define SUB_REALLOC $Sub$$realloc
  211. #define SUPER_CALLOC $Super$$calloc
  212. #define SUB_CALLOC $Sub$$calloc
  213. #define SUPER_FREE $Super$$free
  214. #define SUB_FREE $Sub$$free
  215. #elif defined(__ICCARM__)
  216. #define SUPER_MALLOC $Super$$__iar_dlmalloc
  217. #define SUB_MALLOC $Sub$$__iar_dlmalloc
  218. #define SUPER_REALLOC $Super$$__iar_dlrealloc
  219. #define SUB_REALLOC $Sub$$__iar_dlrealloc
  220. #define SUPER_CALLOC $Super$$__iar_dlcalloc
  221. #define SUB_CALLOC $Sub$$__iar_dlcalloc
  222. #define SUPER_FREE $Super$$__iar_dlfree
  223. #define SUB_FREE $Sub$$__iar_dlfree
  224. #endif
  225. /* Enable hooking of memory function only if tracing is also enabled */
  226. #if defined(MBED_MEM_TRACING_ENABLED) || defined(MBED_HEAP_STATS_ENABLED)
  227. extern "C" {
  228. void *SUPER_MALLOC(size_t size);
  229. void *SUPER_REALLOC(void *ptr, size_t size);
  230. void *SUPER_CALLOC(size_t nmemb, size_t size);
  231. void SUPER_FREE(void *ptr);
  232. void *malloc_wrapper(size_t size, void *caller);
  233. void free_wrapper(void *ptr, void *caller);
  234. }
  235. extern "C" void *SUB_MALLOC(size_t size)
  236. {
  237. return malloc_wrapper(size, MBED_CALLER_ADDR());
  238. }
  239. extern "C" void *malloc_wrapper(size_t size, void *caller)
  240. {
  241. void *ptr = NULL;
  242. #ifdef MBED_MEM_TRACING_ENABLED
  243. mbed_mem_trace_lock();
  244. #endif
  245. #ifdef MBED_HEAP_STATS_ENABLED
  246. malloc_stats_mutex->lock();
  247. alloc_info_t *alloc_info = (alloc_info_t *)SUPER_MALLOC(size + sizeof(alloc_info_t));
  248. if (alloc_info != NULL) {
  249. alloc_info->size = size;
  250. ptr = (void *)(alloc_info + 1);
  251. heap_stats.current_size += size;
  252. heap_stats.total_size += size;
  253. heap_stats.alloc_cnt += 1;
  254. if (heap_stats.current_size > heap_stats.max_size) {
  255. heap_stats.max_size = heap_stats.current_size;
  256. }
  257. } else {
  258. heap_stats.alloc_fail_cnt += 1;
  259. }
  260. malloc_stats_mutex->unlock();
  261. #else // #ifdef MBED_HEAP_STATS_ENABLED
  262. ptr = SUPER_MALLOC(size);
  263. #endif // #ifdef MBED_HEAP_STATS_ENABLED
  264. #ifdef MBED_MEM_TRACING_ENABLED
  265. mbed_mem_trace_malloc(ptr, size, caller);
  266. mbed_mem_trace_unlock();
  267. #endif // #ifdef MBED_MEM_TRACING_ENABLED
  268. return ptr;
  269. }
  270. extern "C" void *SUB_REALLOC(void *ptr, size_t size)
  271. {
  272. void *new_ptr = NULL;
  273. #ifdef MBED_MEM_TRACING_ENABLED
  274. mbed_mem_trace_lock();
  275. #endif
  276. #ifdef MBED_HEAP_STATS_ENABLED
  277. // Note - no lock needed since malloc and free are thread safe
  278. // Get old size
  279. uint32_t old_size = 0;
  280. if (ptr != NULL) {
  281. alloc_info_t *alloc_info = ((alloc_info_t *)ptr) - 1;
  282. old_size = alloc_info->size;
  283. }
  284. // Allocate space
  285. if (size != 0) {
  286. new_ptr = malloc(size);
  287. }
  288. // If the new buffer has been allocated copy the data to it
  289. // and free the old buffer
  290. if (new_ptr != NULL) {
  291. uint32_t copy_size = (old_size < size) ? old_size : size;
  292. memcpy(new_ptr, (void *)ptr, copy_size);
  293. free(ptr);
  294. }
  295. #else // #ifdef MBED_HEAP_STATS_ENABLED
  296. new_ptr = SUPER_REALLOC(ptr, size);
  297. #endif // #ifdef MBED_HEAP_STATS_ENABLED
  298. #ifdef MBED_MEM_TRACING_ENABLED
  299. mbed_mem_trace_realloc(new_ptr, ptr, size, MBED_CALLER_ADDR());
  300. mbed_mem_trace_unlock();
  301. #endif // #ifdef MBED_MEM_TRACING_ENABLED
  302. return new_ptr;
  303. }
  304. extern "C" void *SUB_CALLOC(size_t nmemb, size_t size)
  305. {
  306. void *ptr = NULL;
  307. #ifdef MBED_MEM_TRACING_ENABLED
  308. mbed_mem_trace_lock();
  309. #endif
  310. #ifdef MBED_HEAP_STATS_ENABLED
  311. // Note - no lock needed since malloc is thread safe
  312. ptr = malloc(nmemb * size);
  313. if (ptr != NULL) {
  314. memset(ptr, 0, nmemb * size);
  315. }
  316. #else // #ifdef MBED_HEAP_STATS_ENABLED
  317. ptr = SUPER_CALLOC(nmemb, size);
  318. #endif // #ifdef MBED_HEAP_STATS_ENABLED
  319. #ifdef MBED_MEM_TRACING_ENABLED
  320. mbed_mem_trace_calloc(ptr, nmemb, size, MBED_CALLER_ADDR());
  321. mbed_mem_trace_unlock();
  322. #endif // #ifdef MBED_MEM_TRACING_ENABLED
  323. return ptr;
  324. }
  325. extern "C" void SUB_FREE(void *ptr)
  326. {
  327. free_wrapper(ptr, MBED_CALLER_ADDR());
  328. }
  329. extern "C" void free_wrapper(void *ptr, void *caller)
  330. {
  331. #ifdef MBED_MEM_TRACING_ENABLED
  332. mbed_mem_trace_lock();
  333. #endif
  334. #ifdef MBED_HEAP_STATS_ENABLED
  335. malloc_stats_mutex->lock();
  336. alloc_info_t *alloc_info = NULL;
  337. if (ptr != NULL) {
  338. alloc_info = ((alloc_info_t *)ptr) - 1;
  339. heap_stats.current_size -= alloc_info->size;
  340. heap_stats.alloc_cnt -= 1;
  341. }
  342. SUPER_FREE((void *)alloc_info);
  343. malloc_stats_mutex->unlock();
  344. #else // #ifdef MBED_HEAP_STATS_ENABLED
  345. SUPER_FREE(ptr);
  346. #endif // #ifdef MBED_HEAP_STATS_ENABLED
  347. #ifdef MBED_MEM_TRACING_ENABLED
  348. mbed_mem_trace_free(ptr, caller);
  349. mbed_mem_trace_unlock();
  350. #endif // #ifdef MBED_MEM_TRACING_ENABLED
  351. }
  352. #endif // #if defined(MBED_MEM_TRACING_ENABLED) || defined(MBED_HEAP_STATS_ENABLED)
  353. /******************************************************************************/
  354. /* Allocation wrappers for other toolchains are not supported yet */
  355. /******************************************************************************/
  356. #else
  357. #ifdef MBED_MEM_TRACING_ENABLED
  358. #error Memory tracing is not supported with the current toolchain.
  359. #endif
  360. #ifdef MBED_HEAP_STATS_ENABLED
  361. #error Heap statistics are not supported with the current toolchain.
  362. #endif
  363. #endif // #if defined(TOOLCHAIN_GCC)