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