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