5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002, 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
22 #ifdef SILC_STACKTRACE
24 static void *st_blocks = NULL;
25 static unsigned long st_blocks_count = 0;
26 static SilcBool dump = FALSE;
27 static SilcBool malloc_check = FALSE;
30 #define SILC_ST_DEPTH 15
32 #define SILC_ST_DEPTH 8
33 #endif /* SILC_DEBUG */
35 /* Memory block with stack trace */
36 typedef struct SilcStBlockStruct {
37 unsigned int dumpped : 1; /* Block is dumpped */
38 unsigned int depth : 8; /* Depth of stack trace */
39 unsigned int line : 23; /* Allocation line in program */
40 void *stack[SILC_ST_DEPTH]; /* Stack trace */
41 const char *file; /* Allocation file in program */
42 unsigned long size; /* Allocated memory size */
43 struct SilcStBlockStruct *next;
44 struct SilcStBlockStruct *prev;
47 /* Get current frame pointer */
48 #define SILC_ST_GET_FP(ret_fp) \
51 asm volatile ("movl %%ebp, %0" : "=r" (cfp)); \
55 #define SILC_ST_GET_SIZE(size) ((size + sizeof(struct SilcStBlockStruct)))
56 #define SILC_ST_GET_STACK(p) ((SilcStBlock)(((unsigned char *)p) - \
57 sizeof(struct SilcStBlockStruct)))
58 #define SILC_ST_GET_PTR(p) (((unsigned char *)p) + \
59 sizeof(struct SilcStBlockStruct))
61 void silc_st_stacktrace(SilcStBlock stack)
71 /* Linux libc malloc check */
72 setenv("MALLOC_CHECK_", "2", 1);
74 /* NetBSD malloc check */
75 setenv("MALLOC_OPTIONS", "AJ", 1);
82 for (stack->depth = 0; fp; stack->depth++) {
83 if (stack->depth == SILC_ST_DEPTH)
86 /* Get program pointer and frame pointer from this frame */
87 stack->stack[stack->depth] = *((void **)(((unsigned char *)fp) + 4));
92 void *silc_st_malloc(size_t size, const char *file, int line)
94 SilcStBlock stack = (SilcStBlock)malloc(SILC_ST_GET_SIZE(size));
95 assert(stack != NULL);
101 silc_st_stacktrace(stack);
103 stack->next = st_blocks;
106 ((SilcStBlock)st_blocks)->prev = stack;
110 return SILC_ST_GET_PTR(stack);
113 void *silc_st_calloc(size_t items, size_t size, const char *file, int line)
115 void *addr = (void *)silc_st_malloc(items * size, file, line);
116 memset(addr, 0, items * size);
120 void *silc_st_realloc(void *ptr, size_t size, const char *file, int line)
125 return silc_st_malloc(size, file, line);
127 stack = SILC_ST_GET_STACK(ptr);
128 if (stack->size >= size) {
132 void *addr = (void *)silc_st_malloc(size, file, line);
133 memcpy(addr, ptr, stack->size);
134 silc_st_free(ptr, file, line);
139 void silc_st_free(void *ptr, const char *file, int line)
146 stack = SILC_ST_GET_STACK(ptr);
148 stack->next->prev = stack->prev;
150 stack->prev->next = stack->next;
152 st_blocks = stack->next;
156 memset(stack, 'F', SILC_ST_GET_SIZE(stack->size));
160 void *silc_st_memdup(const void *ptr, size_t size, const char *file, int line)
162 unsigned char *addr = (unsigned char *)silc_st_malloc(size + 1, file, line);
163 memcpy((void *)addr, ptr, size);
168 void *silc_st_strdup(const char *string, const char *file, int line)
170 return silc_st_memdup(string, strlen(string), file, line);
173 /* Dumps the stack into file if there are leaks. The file can be read
174 with a special stacktrace tool. */
176 void silc_st_dump(void)
178 SilcStBlock stack, s;
179 unsigned long leaks = 0, blocks, bytes;
183 for (stack = st_blocks; stack; stack = stack->next) {
192 fp = fopen("stacktrace.log", "wb");
197 for (s = stack; s; s = s->next) {
198 if (s->file == stack->file && s->line == stack->line &&
199 s->depth == stack->depth &&
200 !memcmp(s->stack, stack->stack,
201 (s->depth * sizeof(stack->stack[0])))) {
209 fprintf(fp, "<stacktrace>%s:%d: #blocks=%lu, bytes=%lu\n",
210 stack->file, stack->line, blocks, bytes);
211 for (i = 0; i < stack->depth; i++)
212 fprintf(fp, "\tpc=%p\n", stack->stack[i]);
217 fprintf(stderr, "\nNo memory leaks\n");
220 "-----------------------------------------\n"
221 "-----------------------------------------\n"
222 " Memory leaks dumped to 'stacktrace.log'\n"
223 " Leaks: %lu leaks, %lu blocks\n"
224 "-----------------------------------------\n"
225 "-----------------------------------------\n",
226 leaks, st_blocks_count);
229 if (fp && fp != stderr)
233 #endif /* SILC_STACKTRACE */