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