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