astmm.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /*
  2. * Asterisk -- A telephony toolkit for Linux.
  3. *
  4. * Channel Variables
  5. *
  6. * Copyright (C) 2002, Mark Spencer
  7. *
  8. * Mark Spencer <markster@linux-support.net>
  9. *
  10. * This program is free software, distributed under the terms of
  11. * the GNU General Public License
  12. */
  13. #ifdef __AST_DEBUG_MALLOC
  14. #include <malloc.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <time.h>
  18. #include <asterisk/cli.h>
  19. #include <asterisk/logger.h>
  20. #include <asterisk/options.h>
  21. #include <asterisk/lock.h>
  22. #define SOME_PRIME 563
  23. #define FUNC_CALLOC 1
  24. #define FUNC_MALLOC 2
  25. #define FUNC_REALLOC 3
  26. #define FUNC_STRDUP 4
  27. #define FUNC_STRNDUP 5
  28. #define FUNC_VASPRINTF 6
  29. /* Undefine all our macros */
  30. #undef malloc
  31. #undef calloc
  32. #undef realloc
  33. #undef strdup
  34. #undef strndup
  35. #undef free
  36. #undef vasprintf
  37. static FILE *mmlog;
  38. static struct ast_region {
  39. struct ast_region *next;
  40. char file[40];
  41. char func[40];
  42. int lineno;
  43. int which;
  44. size_t len;
  45. unsigned char data[0];
  46. } *regions[SOME_PRIME];
  47. #define HASH(a) \
  48. (((unsigned long)(a)) % SOME_PRIME)
  49. AST_MUTEX_DEFINE_STATIC(reglock);
  50. AST_MUTEX_DEFINE_STATIC(showmemorylock);
  51. static inline void *__ast_alloc_region(size_t size, int which, const char *file, int lineno, const char *func)
  52. {
  53. struct ast_region *reg;
  54. void *ptr=NULL;
  55. int hash;
  56. reg = malloc(size + sizeof(struct ast_region));
  57. ast_mutex_lock(&reglock);
  58. if (reg) {
  59. strncpy(reg->file, file, sizeof(reg->file) - 1);
  60. reg->file[sizeof(reg->file) - 1] = '\0';
  61. strncpy(reg->func, func, sizeof(reg->func) - 1);
  62. reg->func[sizeof(reg->func) - 1] = '\0';
  63. reg->lineno = lineno;
  64. reg->len = size;
  65. reg->which = which;
  66. ptr = reg->data;
  67. hash = HASH(ptr);
  68. reg->next = regions[hash];
  69. regions[hash] = reg;
  70. }
  71. ast_mutex_unlock(&reglock);
  72. if (!reg) {
  73. fprintf(stderr, "Out of memory :(\n");
  74. if (mmlog) {
  75. fprintf(mmlog, "%ld - Out of memory\n", time(NULL));
  76. fflush(mmlog);
  77. }
  78. }
  79. return ptr;
  80. }
  81. static inline size_t __ast_sizeof_region(void *ptr)
  82. {
  83. int hash = HASH(ptr);
  84. struct ast_region *reg;
  85. size_t len = 0;
  86. ast_mutex_lock(&reglock);
  87. reg = regions[hash];
  88. while(reg) {
  89. if (reg->data == ptr) {
  90. len = reg->len;
  91. break;
  92. }
  93. reg = reg->next;
  94. }
  95. ast_mutex_unlock(&reglock);
  96. return len;
  97. }
  98. static void __ast_free_region(void *ptr, const char *file, int lineno, const char *func)
  99. {
  100. int hash = HASH(ptr);
  101. struct ast_region *reg, *prev = NULL;
  102. ast_mutex_lock(&reglock);
  103. reg = regions[hash];
  104. while(reg) {
  105. if (reg->data == ptr) {
  106. if (prev)
  107. prev->next = reg->next;
  108. else
  109. regions[hash] = reg->next;
  110. break;
  111. }
  112. prev = reg;
  113. reg = reg->next;
  114. }
  115. ast_mutex_unlock(&reglock);
  116. if (reg) {
  117. free(reg);
  118. } else {
  119. fprintf(stderr, "WARNING: Freeing unused memory at %p, in %s of %s, line %d\n",
  120. ptr, func, file, lineno);
  121. if (mmlog) {
  122. fprintf(mmlog, "%ld - WARNING: Freeing unused memory at %p, in %s of %s, line %d\n", time(NULL),
  123. ptr, func, file, lineno);
  124. fflush(mmlog);
  125. }
  126. }
  127. }
  128. void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func)
  129. {
  130. void *ptr;
  131. ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func);
  132. if (ptr)
  133. memset(ptr, 0, size * nmemb);
  134. return ptr;
  135. }
  136. void *__ast_malloc(size_t size, const char *file, int lineno, const char *func)
  137. {
  138. return __ast_alloc_region(size, FUNC_MALLOC, file, lineno, func);
  139. }
  140. void __ast_free(void *ptr, const char *file, int lineno, const char *func)
  141. {
  142. __ast_free_region(ptr, file, lineno, func);
  143. }
  144. void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func)
  145. {
  146. void *tmp;
  147. size_t len=0;
  148. if (ptr) {
  149. len = __ast_sizeof_region(ptr);
  150. if (!len) {
  151. fprintf(stderr, "WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n",
  152. ptr, func, file, lineno);
  153. if (mmlog) {
  154. fprintf(mmlog, "%ld - WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n",
  155. time(NULL), ptr, func, file, lineno);
  156. fflush(mmlog);
  157. }
  158. return NULL;
  159. }
  160. }
  161. tmp = __ast_alloc_region(size, FUNC_REALLOC, file, lineno, func);
  162. if (tmp) {
  163. if (len > size)
  164. len = size;
  165. if (ptr) {
  166. memcpy(tmp, ptr, len);
  167. __ast_free_region(ptr, file, lineno, func);
  168. }
  169. }
  170. return tmp;
  171. }
  172. char *__ast_strdup(const char *s, const char *file, int lineno, const char *func)
  173. {
  174. size_t len;
  175. void *ptr;
  176. if (!s)
  177. return NULL;
  178. len = strlen(s) + 1;
  179. ptr = __ast_alloc_region(len, FUNC_STRDUP, file, lineno, func);
  180. if (ptr)
  181. strcpy(ptr, s);
  182. return ptr;
  183. }
  184. char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func)
  185. {
  186. size_t len;
  187. void *ptr;
  188. if (!s)
  189. return NULL;
  190. len = strlen(s) + 1;
  191. if (len > n)
  192. len = n;
  193. ptr = __ast_alloc_region(len, FUNC_STRNDUP, file, lineno, func);
  194. if (ptr)
  195. strcpy(ptr, s);
  196. return ptr;
  197. }
  198. int __ast_vasprintf(char **strp, const char *fmt, va_list ap, const char *file, int lineno, const char *func)
  199. {
  200. int n, size = strlen(fmt) + 1;
  201. if ((*strp = __ast_alloc_region(size, FUNC_VASPRINTF, file, lineno, func)) == NULL)
  202. return -1;
  203. for (;;) {
  204. n = vsnprintf(*strp, size, fmt, ap);
  205. if (n > -1 && n < size)
  206. return n;
  207. if (n > -1) /* glibc 2.1 */
  208. size = n+1;
  209. else /* glibc 2.0 */
  210. size *= 2;
  211. if ((*strp = __ast_realloc(*strp, size, file, lineno, func)) == NULL)
  212. return -1;
  213. }
  214. }
  215. static int handle_show_memory(int fd, int argc, char *argv[])
  216. {
  217. char *fn = NULL;
  218. int x;
  219. struct ast_region *reg;
  220. unsigned int len=0;
  221. int count = 0;
  222. if (argc >3)
  223. fn = argv[3];
  224. /* try to lock applications list ... */
  225. ast_mutex_lock(&showmemorylock);
  226. for (x=0;x<SOME_PRIME;x++) {
  227. reg = regions[x];
  228. while(reg) {
  229. if (!fn || !strcasecmp(fn, reg->file)) {
  230. ast_cli(fd, "%10d bytes allocated in %20s at line %5d of %s\n", reg->len, reg->func, reg->lineno, reg->file);
  231. len += reg->len;
  232. count++;
  233. }
  234. reg = reg->next;
  235. }
  236. }
  237. ast_cli(fd, "%d bytes allocated %d units total\n", len, count);
  238. ast_mutex_unlock(&showmemorylock);
  239. return RESULT_SUCCESS;
  240. }
  241. struct file_summary {
  242. char fn[80];
  243. int len;
  244. int count;
  245. struct file_summary *next;
  246. };
  247. static int handle_show_memory_summary(int fd, int argc, char *argv[])
  248. {
  249. char *fn = NULL;
  250. int x;
  251. struct ast_region *reg;
  252. unsigned int len=0;
  253. int count = 0;
  254. struct file_summary *list = NULL, *cur;
  255. if (argc >3)
  256. fn = argv[3];
  257. /* try to lock applications list ... */
  258. ast_mutex_lock(&reglock);
  259. for (x=0;x<SOME_PRIME;x++) {
  260. reg = regions[x];
  261. while(reg) {
  262. if (!fn || !strcasecmp(fn, reg->file)) {
  263. cur = list;
  264. while(cur) {
  265. if ((!fn && !strcmp(cur->fn, reg->file)) || (fn && !strcmp(cur->fn, reg->func)))
  266. break;
  267. cur = cur->next;
  268. }
  269. if (!cur) {
  270. cur = alloca(sizeof(struct file_summary));
  271. memset(cur, 0, sizeof(struct file_summary));
  272. strncpy(cur->fn, fn ? reg->func : reg->file, sizeof(cur->fn) - 1);
  273. cur->next = list;
  274. list = cur;
  275. }
  276. cur->len += reg->len;
  277. cur->count++;
  278. }
  279. reg = reg->next;
  280. }
  281. }
  282. ast_mutex_unlock(&reglock);
  283. /* Dump the whole list */
  284. while(list) {
  285. cur = list;
  286. len += list->len;
  287. count += list->count;
  288. if (fn)
  289. ast_cli(fd, "%10d bytes in %5d allocations in function '%s' of '%s'\n", list->len, list->count, list->fn, fn);
  290. else
  291. ast_cli(fd, "%10d bytes in %5d allocations in file '%s'\n", list->len, list->count, list->fn);
  292. list = list->next;
  293. #if 0
  294. free(cur);
  295. #endif
  296. }
  297. ast_cli(fd, "%d bytes allocated %d units total\n", len, count);
  298. return RESULT_SUCCESS;
  299. }
  300. static char show_memory_help[] =
  301. "Usage: show memory allocations [<file>]\n"
  302. " Dumps a list of all segments of allocated memory, optionally\n"
  303. "limited to those from a specific file\n";
  304. static char show_memory_summary_help[] =
  305. "Usage: show memory summary [<file>]\n"
  306. " Summarizes heap memory allocations by file, or optionally\n"
  307. "by function, if a file is specified\n";
  308. static struct ast_cli_entry show_memory_allocations_cli =
  309. { { "show", "memory", "allocations", NULL },
  310. handle_show_memory, "Display outstanding memory allocations",
  311. show_memory_help };
  312. static struct ast_cli_entry show_memory_summary_cli =
  313. { { "show", "memory", "summary", NULL },
  314. handle_show_memory_summary, "Summarize outstanding memory allocations",
  315. show_memory_summary_help };
  316. void __ast_mm_init(void)
  317. {
  318. ast_cli_register(&show_memory_allocations_cli);
  319. ast_cli_register(&show_memory_summary_cli);
  320. mmlog = fopen("/var/log/asterisk/mmlog", "a+");
  321. if (option_verbose)
  322. ast_verbose("Asterisk Malloc Debugger Started (see /var/log/asterisk/mmlog)\n");
  323. if (mmlog) {
  324. fprintf(mmlog, "%ld - New session\n", time(NULL));
  325. fflush(mmlog);
  326. }
  327. }
  328. #endif