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.
20 #include "silcincludes.h"
22 #ifdef SILC_STACKTRACE
24 static void *st_blocks = NULL;
25 static unsigned long st_blocks_count = 0;
26 static int dump = FALSE;
28 #define SILC_ST_DEPTH 10
30 /* Memory block with stack trace */
31 typedef struct SilcStBlockStruct {
32 unsigned int dumpped : 1; /* Block is dumpped */
33 unsigned int depth : 8; /* Depth of stack trace */
34 unsigned int line : 23; /* Allocation line in program */
35 void *stack[SILC_ST_DEPTH]; /* Stack trace */
36 const char *file; /* Allocation file in program */
37 unsigned long size; /* Allocated memory size */
38 struct SilcStBlockStruct *next;
39 struct SilcStBlockStruct *prev;
42 /* Get current frame pointer */
43 #define SILC_ST_GET_FP(ret_fp) \
46 asm volatile ("movl %%ebp, %0" : "=r" (cfp)); \
50 #define SILC_ST_GET_SIZE(size) ((size + sizeof(struct SilcStBlockStruct)))
51 #define SILC_ST_GET_STACK(p) ((SilcStBlock)(((unsigned char *)p) - \
52 sizeof(struct SilcStBlockStruct)))
53 #define SILC_ST_GET_PTR(p) (((unsigned char *)p) + \
54 sizeof(struct SilcStBlockStruct))
56 void silc_st_stacktrace(SilcStBlock stack)
67 for (stack->depth = 0; fp; stack->depth++) {
68 if (stack->depth == SILC_ST_DEPTH)
71 /* Get program pointer and frame pointer from this frame */
72 stack->stack[stack->depth] = *((void **)(((unsigned char *)fp) + 4));
77 void *silc_st_malloc(size_t size, const char *file, int line)
79 SilcStBlock stack = (SilcStBlock)malloc(SILC_ST_GET_SIZE(size));
80 assert(stack != NULL);
86 silc_st_stacktrace(stack);
88 stack->next = st_blocks;
91 ((SilcStBlock)st_blocks)->prev = stack;
95 return SILC_ST_GET_PTR(stack);
98 void *silc_st_calloc(size_t items, size_t size, const char *file, int line)
100 void *addr = (void *)silc_st_malloc(items * size, file, line);
101 memset(addr, 0, items * size);
105 void *silc_st_realloc(void *ptr, size_t size, const char *file, int line)
110 return silc_st_malloc(size, file, line);
112 stack = SILC_ST_GET_STACK(ptr);
113 if (stack->size >= size) {
117 void *addr = (void *)silc_st_malloc(size, file, line);
118 memcpy(addr, ptr, stack->size);
119 silc_st_free(ptr, file, line);
124 void silc_st_free(void *ptr, const char *file, int line)
131 stack = SILC_ST_GET_STACK(ptr);
133 stack->next->prev = stack->prev;
135 stack->prev->next = stack->next;
137 st_blocks = stack->next;
143 void *silc_st_memdup(const void *ptr, size_t size, const char *file, int line)
145 unsigned char *addr = (unsigned char *)silc_st_malloc(size + 1, file, line);
146 memcpy((void *)addr, ptr, size);
151 void *silc_st_strdup(const char *string, const char *file, int line)
153 return silc_st_memdup(string, strlen(string), file, line);
156 /* Dumps the stack into file if there are leaks. The file can be read
157 with a special stacktrace tool. */
159 void silc_st_dump(void)
161 SilcStBlock stack, s;
162 unsigned long leaks = 0, blocks, bytes;
166 for (stack = st_blocks; stack; stack = stack->next) {
175 fp = fopen("stacktrace.log", "wb");
180 for (s = stack; s; s = s->next) {
181 if (s->file == stack->file && s->line == stack->line &&
182 s->depth == stack->depth &&
183 !memcmp(s->stack, stack->stack,
184 (s->depth * sizeof(stack->stack[0])))) {
192 fprintf(fp, "<stacktrace>%s:%d: #blocks=%lu, bytes=%lu\n",
193 stack->file, stack->line, blocks, bytes);
194 for (i = 0; i < stack->depth; i++)
195 fprintf(fp, "<pc>%p\n", stack->stack[i]);
200 fprintf(stderr, "\nNo memory leaks\n");
203 "-----------------------------------------\n"
204 "-----------------------------------------\n"
205 " Memory leaks dumped to 'stacktrace.log'\n"
206 " Leaks: %lu leaks, %lu blocks\n"
207 "-----------------------------------------\n"
208 "-----------------------------------------\n",
209 leaks, st_blocks_count);
212 if (fp && fp != stderr)
216 #endif /* SILC_STACKTRACE */