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
AST_MUTEX_DEFINE_STATIC(reglock);
00062
AST_MUTEX_DEFINE_STATIC(showmemorylock);
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