5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 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;
29 #define SILC_ST_DEPTH 10
31 /* Memory block with stack trace */
32 typedef struct SilcStBlockStruct {
33 unsigned int dumpped : 1; /* Block is dumpped */
34 unsigned int depth : 8; /* Depth of stack trace */
35 unsigned int line : 23; /* Allocation line in program */
36 void *stack[SILC_ST_DEPTH]; /* Stack trace */
37 const char *file; /* Allocation file in program */
38 unsigned long size; /* Allocated memory size */
39 struct SilcStBlockStruct *next;
40 struct SilcStBlockStruct *prev;
43 /* Get current frame pointer */
44 #define SILC_ST_GET_FP(ret_fp) \
47 asm volatile ("movl %%ebp, %0" : "=r" (cfp)); \
51 #define SILC_ST_GET_SIZE(size) ((size + sizeof(struct SilcStBlockStruct)))
52 #define SILC_ST_GET_STACK(p) ((SilcStBlock)(((unsigned char *)p) - \
53 sizeof(struct SilcStBlockStruct)))
54 #define SILC_ST_GET_PTR(p) (((unsigned char *)p) + \
55 sizeof(struct SilcStBlockStruct))
57 void silc_st_stacktrace(SilcStBlock stack)
67 /* Linux libc malloc check */
68 setenv("MALLOC_CHECK_", "2", 1);
70 /* NetBSD malloc check */
71 setenv("MALLOC_OPTIONS", "AJ", 1);
78 for (stack->depth = 0; fp; stack->depth++) {
79 if (stack->depth == SILC_ST_DEPTH)
82 /* Get program pointer and frame pointer from this frame */
83 stack->stack[stack->depth] = *((void **)(((unsigned char *)fp) + 4));
88 void *silc_st_malloc(size_t size, const char *file, int line)
90 SilcStBlock stack = (SilcStBlock)malloc(SILC_ST_GET_SIZE(size));
91 assert(stack != NULL);
97 silc_st_stacktrace(stack);
99 stack->next = st_blocks;
102 ((SilcStBlock)st_blocks)->prev = stack;
106 return SILC_ST_GET_PTR(stack);
109 void *silc_st_calloc(size_t items, size_t size, const char *file, int line)
111 void *addr = (void *)silc_st_malloc(items * size, file, line);
112 memset(addr, 0, items * size);
116 void *silc_st_realloc(void *ptr, size_t size, const char *file, int line)
121 return silc_st_malloc(size, file, line);
123 stack = SILC_ST_GET_STACK(ptr);
124 if (stack->size >= size) {
128 void *addr = (void *)silc_st_malloc(size, file, line);
129 memcpy(addr, ptr, stack->size);
130 silc_st_free(ptr, file, line);
135 void silc_st_free(void *ptr, const char *file, int line)
142 stack = SILC_ST_GET_STACK(ptr);
144 stack->next->prev = stack->prev;
146 stack->prev->next = stack->next;
148 st_blocks = stack->next;
154 void *silc_st_memdup(const void *ptr, size_t size, const char *file, int line)
156 unsigned char *addr = (unsigned char *)silc_st_malloc(size + 1, file, line);
157 memcpy((void *)addr, ptr, size);
162 void *silc_st_strdup(const char *string, const char *file, int line)
164 return silc_st_memdup(string, strlen(string), file, line);
167 /* Dumps the stack into file if there are leaks. The file can be read
168 with a special stacktrace tool. */
170 void silc_st_dump(void)
172 SilcStBlock stack, s;
173 unsigned long leaks = 0, blocks, bytes;
177 for (stack = st_blocks; stack; stack = stack->next) {
186 fp = fopen("stacktrace.log", "wb");
191 for (s = stack; s; s = s->next) {
192 if (s->file == stack->file && s->line == stack->line &&
193 s->depth == stack->depth &&
194 !memcmp(s->stack, stack->stack,
195 (s->depth * sizeof(stack->stack[0])))) {
203 fprintf(fp, "<stacktrace>%s:%d: #blocks=%lu, bytes=%lu\n",
204 stack->file, stack->line, blocks, bytes);
205 for (i = 0; i < stack->depth; i++)
206 fprintf(fp, "<pc>%p\n", stack->stack[i]);
211 fprintf(stderr, "\nNo memory leaks\n");
214 "-----------------------------------------\n"
215 "-----------------------------------------\n"
216 " Memory leaks dumped to 'stacktrace.log'\n"
217 " Leaks: %lu leaks, %lu blocks\n"
218 "-----------------------------------------\n"
219 "-----------------------------------------\n",
220 leaks, st_blocks_count);
223 if (fp && fp != stderr)
227 #endif /* SILC_STACKTRACE */