x86-64 compile fixes and cleanups
[asterisk/asterisk.git] / astmm.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Channel Variables
5  * 
6  * Copyright (C) 2002, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14
15
16 #ifdef __AST_DEBUG_MALLOC
17
18 #include <malloc.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <pthread.h>
22 #include <time.h>
23 #include <asterisk/cli.h>
24 #include <asterisk/logger.h>
25 #include <asterisk/options.h>
26 #include <asterisk/lock.h>
27
28 #define SOME_PRIME 563
29
30 #define FUNC_CALLOC             1
31 #define FUNC_MALLOC             2
32 #define FUNC_REALLOC    3
33 #define FUNC_STRDUP             4
34 #define FUNC_STRNDUP    5
35 #define FUNC_VASPRINTF  6
36
37 /* Undefine all our macros */
38 #undef malloc
39 #undef calloc
40 #undef realloc
41 #undef strdup
42 #undef strndup
43 #undef free
44 #undef vasprintf
45
46 static FILE *mmlog;
47
48 static struct ast_region {
49         struct ast_region *next;
50         char file[40];
51         char func[40];
52         int lineno;
53         int which;
54         size_t len;
55         unsigned char data[0];
56 } *regions[SOME_PRIME];
57
58 #define HASH(a) \
59         (((unsigned long)(a)) % SOME_PRIME)
60         
61 AST_MUTEX_DEFINE_STATIC(reglock);
62 AST_MUTEX_DEFINE_STATIC(showmemorylock);
63
64 static inline void *__ast_alloc_region(size_t size, int which, const char *file, int lineno, const char *func)
65 {
66         struct ast_region *reg;
67         void *ptr=NULL;
68         int hash;
69         reg = malloc(size + sizeof(struct ast_region));
70         ast_mutex_lock(&reglock);
71         if (reg) {
72                 strncpy(reg->file, file, sizeof(reg->file) - 1);
73                 reg->file[sizeof(reg->file) - 1] = '\0';
74                 strncpy(reg->func, func, sizeof(reg->func) - 1);
75                 reg->func[sizeof(reg->func) - 1] = '\0';
76                 reg->lineno = lineno;
77                 reg->len = size;
78                 reg->which = which;
79                 ptr = reg->data;
80                 hash = HASH(ptr);
81                 reg->next = regions[hash];
82                 regions[hash] = reg;
83         }
84         ast_mutex_unlock(&reglock);
85         if (!reg) {
86                 fprintf(stderr, "Out of memory :(\n");
87                 if (mmlog) {
88                         fprintf(mmlog, "%ld - Out of memory\n", time(NULL));
89                         fflush(mmlog);
90                 }
91         }
92         return ptr;
93 }
94
95 static inline size_t __ast_sizeof_region(void *ptr)
96 {
97         int hash = HASH(ptr);
98         struct ast_region *reg;
99         size_t len = 0;
100         
101         ast_mutex_lock(&reglock);
102         reg = regions[hash];
103         while(reg) {
104                 if (reg->data == ptr) {
105                         len = reg->len;
106                         break;
107                 }
108                 reg = reg->next;
109         }
110         ast_mutex_unlock(&reglock);
111         return len;
112 }
113
114 static void __ast_free_region(void *ptr, const char *file, int lineno, const char *func)
115 {
116         int hash = HASH(ptr);
117         struct ast_region *reg, *prev = NULL;
118         ast_mutex_lock(&reglock);
119         reg = regions[hash];
120         while(reg) {
121                 if (reg->data == ptr) {
122                         if (prev)
123                                 prev->next = reg->next;
124                         else
125                                 regions[hash] = reg->next;
126
127                         break;
128                 }
129                 prev = reg;
130                 reg = reg->next;
131         }
132         ast_mutex_unlock(&reglock);
133         if (reg) {
134                 free(reg);
135         } else {
136                 fprintf(stderr, "WARNING: Freeing unused memory at %p, in %s of %s, line %d\n",
137                         ptr, func, file, lineno);
138                 if (mmlog) {
139                         fprintf(mmlog, "%ld - WARNING: Freeing unused memory at %p, in %s of %s, line %d\n", time(NULL),
140                         ptr, func, file, lineno);
141                         fflush(mmlog);
142                 }
143         }
144 }
145
146 void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) 
147 {
148         void *ptr;
149         ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func);
150         if (ptr) 
151                 memset(ptr, 0, size * nmemb);
152         return ptr;
153 }
154
155 void *__ast_malloc(size_t size, const char *file, int lineno, const char *func) 
156 {
157         return __ast_alloc_region(size, FUNC_MALLOC, file, lineno, func);
158 }
159
160 void __ast_free(void *ptr, const char *file, int lineno, const char *func) 
161 {
162         __ast_free_region(ptr, file, lineno, func);
163 }
164
165 void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func) 
166 {
167         void *tmp;
168         size_t len=0;
169         if (ptr) {
170                 len = __ast_sizeof_region(ptr);
171                 if (!len) {
172                         fprintf(stderr, "WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n",
173                                 ptr, func, file, lineno);
174                         if (mmlog) {
175                                 fprintf(mmlog, "%ld - WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n",
176                                         time(NULL), ptr, func, file, lineno);
177                                 fflush(mmlog);
178                         }
179                         return NULL;
180                 }
181         }
182         tmp = __ast_alloc_region(size, FUNC_REALLOC, file, lineno, func);
183         if (tmp) {
184                 if (len > size)
185                         len = size;
186                 if (ptr) {
187                         memcpy(tmp, ptr, len);
188                         __ast_free_region(ptr, file, lineno, func);
189                 }
190         }
191         return tmp;
192 }
193
194 char *__ast_strdup(const char *s, const char *file, int lineno, const char *func) 
195 {
196         size_t len;
197         void *ptr;
198         if (!s)
199                 return NULL;
200         len = strlen(s) + 1;
201         ptr = __ast_alloc_region(len, FUNC_STRDUP, file, lineno, func);
202         if (ptr)
203                 strcpy(ptr, s);
204         return ptr;
205 }
206
207 char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func) 
208 {
209         size_t len;
210         void *ptr;
211         if (!s)
212                 return NULL;
213         len = strlen(s) + 1;
214         if (len > n)
215                 len = n;
216         ptr = __ast_alloc_region(len, FUNC_STRNDUP, file, lineno, func);
217         if (ptr)
218                 strcpy(ptr, s);
219         return ptr;
220 }
221
222 int __ast_vasprintf(char **strp, const char *fmt, va_list ap, const char *file, int lineno, const char *func) 
223 {
224         int n, size = strlen(fmt) + 1;
225         if ((*strp = __ast_alloc_region(size, FUNC_VASPRINTF, file, lineno, func)) == NULL)
226                 return -1; 
227         for (;;) {
228                 n = vsnprintf(*strp, size, fmt, ap);
229                 if (n > -1 && n < size)
230                         return n;
231                 if (n > -1)     /* glibc 2.1 */
232                         size = n+1;
233                 else            /* glibc 2.0 */
234                         size *= 2;
235                 if ((*strp = __ast_realloc(*strp, size, file, lineno, func)) == NULL)
236                         return -1;
237         }
238 }
239
240 static int handle_show_memory(int fd, int argc, char *argv[])
241 {
242         char *fn = NULL;
243         int x;
244         struct ast_region *reg;
245         unsigned int len=0;
246         int count = 0;
247         if (argc >3) 
248                 fn = argv[3];
249
250         /* try to lock applications list ... */
251         ast_mutex_lock(&showmemorylock);
252
253         for (x=0;x<SOME_PRIME;x++) {
254                 reg = regions[x];
255                 while(reg) {
256                         if (!fn || !strcasecmp(fn, reg->file)) {
257                                 ast_cli(fd, "%10d bytes allocated in %20s at line %5d of %s\n", reg->len, reg->func, reg->lineno, reg->file);
258                                 len += reg->len;
259                                 count++;
260                         }
261                         reg = reg->next;
262                 }
263         }
264         ast_cli(fd, "%d bytes allocated %d units total\n", len, count);
265         ast_mutex_unlock(&showmemorylock);
266         return RESULT_SUCCESS;
267 }
268
269 struct file_summary {
270         char fn[80];
271         int len;
272         int count;
273         struct file_summary *next;
274 };
275
276 static int handle_show_memory_summary(int fd, int argc, char *argv[])
277 {
278         char *fn = NULL;
279         int x;
280         struct ast_region *reg;
281         unsigned int len=0;
282         int count = 0;
283         struct file_summary *list = NULL, *cur;
284         
285         if (argc >3) 
286                 fn = argv[3];
287
288         /* try to lock applications list ... */
289         ast_mutex_lock(&reglock);
290
291         for (x=0;x<SOME_PRIME;x++) {
292                 reg = regions[x];
293                 while(reg) {
294                         if (!fn || !strcasecmp(fn, reg->file)) {
295                                 cur = list;
296                                 while(cur) {
297                                         if ((!fn && !strcmp(cur->fn, reg->file)) || (fn && !strcmp(cur->fn, reg->func)))
298                                                 break;
299                                         cur = cur->next;
300                                 }
301                                 if (!cur) {
302                                         cur = alloca(sizeof(struct file_summary));
303                                         memset(cur, 0, sizeof(struct file_summary));
304                                         strncpy(cur->fn, fn ? reg->func : reg->file, sizeof(cur->fn) - 1);
305                                         cur->next = list;
306                                         list = cur;
307                                 }
308                                 cur->len += reg->len;
309                                 cur->count++;
310                         }
311                         reg = reg->next;
312                 }
313         }
314         ast_mutex_unlock(&reglock);
315         
316         /* Dump the whole list */
317         while(list) {
318                 cur = list;
319                 len += list->len;
320                 count += list->count;
321                 if (fn)
322                         ast_cli(fd, "%10d bytes in %5d allocations in function '%s' of '%s'\n", list->len, list->count, list->fn, fn);
323                 else
324                         ast_cli(fd, "%10d bytes in %5d allocations in file '%s'\n", list->len, list->count, list->fn);
325                 list = list->next;
326 #if 0
327                 free(cur);
328 #endif          
329         }
330         ast_cli(fd, "%d bytes allocated %d units total\n", len, count);
331         return RESULT_SUCCESS;
332 }
333
334 static char show_memory_help[] = 
335 "Usage: show memory allocations [<file>]\n"
336 "       Dumps a list of all segments of allocated memory, optionally\n"
337 "limited to those from a specific file\n";
338
339 static char show_memory_summary_help[] = 
340 "Usage: show memory summary [<file>]\n"
341 "       Summarizes heap memory allocations by file, or optionally\n"
342 "by function, if a file is specified\n";
343
344 static struct ast_cli_entry show_memory_allocations_cli = 
345         { { "show", "memory", "allocations", NULL }, 
346         handle_show_memory, "Display outstanding memory allocations",
347         show_memory_help };
348
349 static struct ast_cli_entry show_memory_summary_cli = 
350         { { "show", "memory", "summary", NULL }, 
351         handle_show_memory_summary, "Summarize outstanding memory allocations",
352         show_memory_summary_help };
353
354
355 void __ast_mm_init(void)
356 {
357         ast_cli_register(&show_memory_allocations_cli);
358         ast_cli_register(&show_memory_summary_cli);
359         mmlog = fopen("/var/log/asterisk/mmlog", "a+");
360         if (option_verbose)
361                 ast_verbose("Asterisk Malloc Debugger Started (see /var/log/asterisk/mmlog)\n");
362         if (mmlog) {
363                 fprintf(mmlog, "%ld - New session\n", time(NULL));
364                 fflush(mmlog);
365         }
366 }
367
368 #endif