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