00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifdef __AST_DEBUG_MALLOC
00026
00027 #include <stdio.h>
00028 #include <string.h>
00029 #include <time.h>
00030
00031 #include "asterisk.h"
00032
00033 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7221 $")
00034
00035 #include "asterisk/cli.h"
00036 #include "asterisk/logger.h"
00037 #include "asterisk/options.h"
00038 #include "asterisk/lock.h"
00039 #include "asterisk/strings.h"
00040
00041 #define SOME_PRIME 563
00042
00043 #define FUNC_CALLOC 1
00044 #define FUNC_MALLOC 2
00045 #define FUNC_REALLOC 3
00046 #define FUNC_STRDUP 4
00047 #define FUNC_STRNDUP 5
00048 #define FUNC_VASPRINTF 6
00049
00050
00051 #undef malloc
00052 #undef calloc
00053 #undef realloc
00054 #undef strdup
00055 #undef strndup
00056 #undef free
00057 #undef vasprintf
00058
00059 #define FENCE_MAGIC 0xdeadbeef
00060
00061 static FILE *mmlog;
00062
00063 static struct ast_region {
00064 struct ast_region *next;
00065 char file[40];
00066 char func[40];
00067 int lineno;
00068 int which;
00069 size_t len;
00070 unsigned int fence;
00071 unsigned char data[0];
00072 } *regions[SOME_PRIME];
00073
00074 #define HASH(a) \
00075 (((unsigned long)(a)) % SOME_PRIME)
00076
00077 AST_MUTEX_DEFINE_STATIC(reglock);
00078 AST_MUTEX_DEFINE_STATIC(showmemorylock);
00079
00080 static inline void *__ast_alloc_region(size_t size, int which, const char *file, int lineno, const char *func)
00081 {
00082 struct ast_region *reg;
00083 void *ptr = NULL;
00084 unsigned int *fence;
00085 int hash;
00086 reg = malloc(size + sizeof(struct ast_region) + sizeof(unsigned int));
00087 ast_mutex_lock(®lock);
00088 if (reg) {
00089 ast_copy_string(reg->file, file, sizeof(reg->file));
00090 reg->file[sizeof(reg->file) - 1] = '\0';
00091 ast_copy_string(reg->func, func, sizeof(reg->func));
00092 reg->func[sizeof(reg->func) - 1] = '\0';
00093 reg->lineno = lineno;
00094 reg->len = size;
00095 reg->which = which;
00096 ptr = reg->data;
00097 hash = HASH(ptr);
00098 reg->next = regions[hash];
00099 regions[hash] = reg;
00100 reg->fence = FENCE_MAGIC;
00101 fence = (ptr + reg->len);
00102 *fence = FENCE_MAGIC;
00103 }
00104 ast_mutex_unlock(®lock);
00105 if (!reg) {
00106 fprintf(stderr, "Out of memory :(\n");
00107 if (mmlog) {
00108 fprintf(mmlog, "%ld - Out of memory\n", time(NULL));
00109 fflush(mmlog);
00110 }
00111 }
00112 return ptr;
00113 }
00114
00115 static inline size_t __ast_sizeof_region(void *ptr)
00116 {
00117 int hash = HASH(ptr);
00118 struct ast_region *reg;
00119 size_t len = 0;
00120
00121 ast_mutex_lock(®lock);
00122 reg = regions[hash];
00123 while (reg) {
00124 if (reg->data == ptr) {
00125 len = reg->len;
00126 break;
00127 }
00128 reg = reg->next;
00129 }
00130 ast_mutex_unlock(®lock);
00131 return len;
00132 }
00133
00134 static void __ast_free_region(void *ptr, const char *file, int lineno, const char *func)
00135 {
00136 int hash = HASH(ptr);
00137 struct ast_region *reg, *prev = NULL;
00138 unsigned int *fence;
00139
00140 ast_mutex_lock(®lock);
00141 reg = regions[hash];
00142 while (reg) {
00143 if (reg->data == ptr) {
00144 if (prev) {
00145 prev->next = reg->next;
00146 } else {
00147 regions[hash] = reg->next;
00148 }
00149 break;
00150 }
00151 prev = reg;
00152 reg = reg->next;
00153 }
00154 ast_mutex_unlock(®lock);
00155 if (reg) {
00156 fence = (unsigned int *)(reg->data + reg->len);
00157 if (reg->fence != FENCE_MAGIC) {
00158 fprintf(stderr, "WARNING: Low fence violation at %p, in %s of %s, line %d\n", reg->data, reg->func, reg->file, reg->lineno);
00159 if (mmlog) {
00160 fprintf(mmlog, "%ld - WARNING: Low fence violation at %p, in %s of %s, line %d\n", time(NULL), reg->data, reg->func, reg->file, reg->lineno);
00161 fflush(mmlog);
00162 }
00163 }
00164 if (*fence != FENCE_MAGIC) {
00165 fprintf(stderr, "WARNING: High fence violation at %p, in %s of %s, line %d\n", reg->data, reg->func, reg->file, reg->lineno);
00166 if (mmlog) {
00167 fprintf(mmlog, "%ld - WARNING: High fence violation at %p, in %s of %s, line %d\n", time(NULL), reg->data, reg->func, reg->file, reg->lineno);
00168 fflush(mmlog);
00169 }
00170 }
00171 free(reg);
00172 } else {
00173 fprintf(stderr, "WARNING: Freeing unused memory at %p, in %s of %s, line %d\n", ptr, func, file, lineno);
00174 if (mmlog) {
00175 fprintf(mmlog, "%ld - WARNING: Freeing unused memory at %p, in %s of %s, line %d\n", time(NULL), ptr, func, file, lineno);
00176 fflush(mmlog);
00177 }
00178 }
00179 }
00180
00181 void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func)
00182 {
00183 void *ptr;
00184 ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func);
00185 if (ptr)
00186 memset(ptr, 0, size * nmemb);
00187 return ptr;
00188 }
00189
00190 void *__ast_malloc(size_t size, const char *file, int lineno, const char *func)
00191 {
00192 return __ast_alloc_region(size, FUNC_MALLOC, file, lineno, func);
00193 }
00194
00195 void __ast_free(void *ptr, const char *file, int lineno, const char *func)
00196 {
00197 __ast_free_region(ptr, file, lineno, func);
00198 }
00199
00200 void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func)
00201 {
00202 void *tmp;
00203 size_t len = 0;
00204 if (ptr) {
00205 len = __ast_sizeof_region(ptr);
00206 if (!len) {
00207 fprintf(stderr, "WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n", ptr, func, file, lineno);
00208 if (mmlog) {
00209 fprintf(mmlog, "%ld - WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n", time(NULL), ptr, func, file, lineno);
00210 fflush(mmlog);
00211 }
00212 return NULL;
00213 }
00214 }
00215 tmp = __ast_alloc_region(size, FUNC_REALLOC, file, lineno, func);
00216 if (tmp) {
00217 if (len > size)
00218 len = size;
00219 if (ptr) {
00220 memcpy(tmp, ptr, len);
00221 __ast_free_region(ptr, file, lineno, func);
00222 }
00223 }
00224 return tmp;
00225 }
00226
00227 char *__ast_strdup(const char *s, const char *file, int lineno, const char *func)
00228 {
00229 size_t len;
00230 void *ptr;
00231 if (!s)
00232 return NULL;
00233 len = strlen(s) + 1;
00234 ptr = __ast_alloc_region(len, FUNC_STRDUP, file, lineno, func);
00235 if (ptr)
00236 strcpy(ptr, s);
00237 return ptr;
00238 }
00239
00240 char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func)
00241 {
00242 size_t len;
00243 void *ptr;
00244 if (!s)
00245 return NULL;
00246 len = strlen(s) + 1;
00247 if (len > n)
00248 len = n;
00249 ptr = __ast_alloc_region(len, FUNC_STRNDUP, file, lineno, func);
00250 if (ptr)
00251 strcpy(ptr, s);
00252 return ptr;
00253 }
00254
00255 int __ast_vasprintf(char **strp, const char *fmt, va_list ap, const char *file, int lineno, const char *func)
00256 {
00257 int size;
00258 va_list ap2;
00259 char s;
00260
00261 *strp = NULL;
00262 va_copy(ap2, ap);
00263 size = vsnprintf(&s, 1, fmt, ap2);
00264 va_end(ap2);
00265 *strp = __ast_alloc_region(size + 1, FUNC_VASPRINTF, file, lineno, func);
00266 if (!*strp)
00267 return -1;
00268 vsnprintf(*strp, size + 1, fmt, ap);
00269
00270 return size;
00271 }
00272
00273 static int handle_show_memory(int fd, int argc, char *argv[])
00274 {
00275 char *fn = NULL;
00276 int x;
00277 struct ast_region *reg;
00278 unsigned int len = 0;
00279 int count = 0;
00280 unsigned int *fence;
00281 if (argc > 3)
00282 fn = argv[3];
00283
00284
00285 ast_mutex_lock(&showmemorylock);
00286
00287 for (x = 0; x < SOME_PRIME; x++) {
00288 reg = regions[x];
00289 while (reg) {
00290 if (!fn || !strcasecmp(fn, reg->file) || !strcasecmp(fn, "anomolies")) {
00291 fence = (unsigned int *)(reg->data + reg->len);
00292 if (reg->fence != FENCE_MAGIC) {
00293 fprintf(stderr, "WARNING: Low fence violation at %p, in %s of %s, line %d\n", reg->data, reg->func, reg->file, reg->lineno);
00294 if (mmlog) {
00295 fprintf(mmlog, "%ld - WARNING: Low fence violation at %p, in %s of %s, line %d\n", time(NULL), reg->data, reg->func, reg-> file, reg->lineno);
00296 fflush(mmlog);
00297 }
00298 }
00299 if (*fence != FENCE_MAGIC) {
00300 fprintf(stderr, "WARNING: High fence violation at %p, in %s of %s, line %d\n", reg->data, reg->func, reg->file, reg->lineno);
00301 if (mmlog) {
00302 fprintf(mmlog, "%ld - WARNING: High fence violation at %p, in %s of %s, line %d\n", time(NULL), reg->data, reg->func, reg->file, reg->lineno);
00303 fflush(mmlog);
00304 }
00305 }
00306 }
00307 if (!fn || !strcasecmp(fn, reg->file)) {
00308 ast_cli(fd, "%10d bytes allocated in %20s at line %5d of %s\n", (int) reg->len, reg->func, reg->lineno, reg->file);
00309 len += reg->len;
00310 count++;
00311 }
00312 reg = reg->next;
00313 }
00314 }
00315 ast_cli(fd, "%d bytes allocated %d units total\n", len, count);
00316 ast_mutex_unlock(&showmemorylock);
00317 return RESULT_SUCCESS;
00318 }
00319
00320 struct file_summary {
00321 char fn[80];
00322 int len;
00323 int count;
00324 struct file_summary *next;
00325 };
00326
00327 static int handle_show_memory_summary(int fd, int argc, char *argv[])
00328 {
00329 char *fn = NULL;
00330 int x;
00331 struct ast_region *reg;
00332 unsigned int len = 0;
00333 int count = 0;
00334 struct file_summary *list = NULL, *cur;
00335
00336 if (argc > 3)
00337 fn = argv[3];
00338
00339
00340 ast_mutex_lock(®lock);
00341
00342 for (x = 0; x < SOME_PRIME; x++) {
00343 reg = regions[x];
00344 while (reg) {
00345 if (!fn || !strcasecmp(fn, reg->file)) {
00346 cur = list;
00347 while (cur) {
00348 if ((!fn && !strcmp(cur->fn, reg->file)) || (fn && !strcmp(cur->fn, reg->func)))
00349 break;
00350 cur = cur->next;
00351 }
00352 if (!cur) {
00353 cur = alloca(sizeof(struct file_summary));
00354 memset(cur, 0, sizeof(struct file_summary));
00355 ast_copy_string(cur->fn, fn ? reg->func : reg->file, sizeof(cur->fn));
00356 cur->next = list;
00357 list = cur;
00358 }
00359 cur->len += reg->len;
00360 cur->count++;
00361 }
00362 reg = reg->next;
00363 }
00364 }
00365 ast_mutex_unlock(®lock);
00366
00367
00368 while (list) {
00369 cur = list;
00370 len += list->len;
00371 count += list->count;
00372 if (fn) {
00373 ast_cli(fd, "%10d bytes in %5d allocations in function '%s' of '%s'\n", list->len, list->count, list->fn, fn);
00374 } else {
00375 ast_cli(fd, "%10d bytes in %5d allocations in file '%s'\n", list->len, list->count, list->fn);
00376 }
00377 list = list->next;
00378 #if 0
00379 free(cur);
00380 #endif
00381 }
00382 ast_cli(fd, "%d bytes allocated %d units total\n", len, count);
00383 return RESULT_SUCCESS;
00384 }
00385
00386 static char show_memory_help[] =
00387 "Usage: show memory allocations [<file>]\n"
00388 " Dumps a list of all segments of allocated memory, optionally\n"
00389 "limited to those from a specific file\n";
00390
00391 static char show_memory_summary_help[] =
00392 "Usage: show memory summary [<file>]\n"
00393 " Summarizes heap memory allocations by file, or optionally\n"
00394 "by function, if a file is specified\n";
00395
00396 static struct ast_cli_entry show_memory_allocations_cli =
00397 { { "show", "memory", "allocations", NULL },
00398 handle_show_memory, "Display outstanding memory allocations",
00399 show_memory_help };
00400
00401 static struct ast_cli_entry show_memory_summary_cli =
00402 { { "show", "memory", "summary", NULL },
00403 handle_show_memory_summary, "Summarize outstanding memory allocations",
00404 show_memory_summary_help };
00405
00406 void __ast_mm_init(void)
00407 {
00408 char filename[80] = "";
00409 ast_cli_register(&show_memory_allocations_cli);
00410 ast_cli_register(&show_memory_summary_cli);
00411
00412 snprintf(filename, sizeof(filename), "%s/mmlog", (char *)ast_config_AST_LOG_DIR);
00413 mmlog = fopen(filename, "a+");
00414 if (option_verbose)
00415 ast_verbose("Asterisk Malloc Debugger Started (see %s))\n", filename);
00416 if (mmlog) {
00417 fprintf(mmlog, "%ld - New session\n", time(NULL));
00418 fflush(mmlog);
00419 }
00420 }
00421
00422 #endif