1 /**
2 * @file debug.h
3 * @author Joe Wingbermuehle
4 * @date 2003-2006
5 *
6 * @brief Debug functions.
7 *
8 */
9
10 #include "debug.h"
11 #include <stdarg.h>
12 #include <stdio.h>
13 #include <string.h>
14
15 /** Emit a message (if compiled with -DDEBUG). */
Debug(const char * str,...)16 void Debug(const char *str, ...)
17 {
18 #ifdef DEBUG
19
20 va_list ap;
21 va_start(ap, str);
22 Assert(str);
23 fprintf(stderr, "DEBUG: ");
24 vfprintf(stderr, str, ap);
25 fprintf(stderr, "\n");
26 va_end(ap);
27
28 #endif /* DEBUG */
29 }
30
31 #ifdef DEBUG
32
33 #define CHECKPOINT_LIST_SIZE 8
34
35 typedef struct MemoryType {
36 const char *file;
37 unsigned int line;
38 size_t size;
39 char *pointer;
40 struct MemoryType *next;
41 } MemoryType;
42
43 static MemoryType *allocations = NULL;
44
45 static const char *checkpointFile[CHECKPOINT_LIST_SIZE];
46 static unsigned int checkpointLine[CHECKPOINT_LIST_SIZE];
47 static unsigned int checkpointOffset;
48
49 /** Start the debugger. */
DEBUG_StartDebug(const char * file,unsigned int line)50 void DEBUG_StartDebug(const char *file, unsigned int line)
51 {
52 unsigned int x;
53 Debug("%s[%u]: debug mode started", file, line);
54 checkpointOffset = 0;
55 for(x = 0; x < CHECKPOINT_LIST_SIZE; x++) {
56 checkpointFile[x] = NULL;
57 checkpointLine[x] = 0;
58 }
59 }
60
61 /** Stop the debugger. */
DEBUG_StopDebug(const char * file,unsigned int line)62 void DEBUG_StopDebug(const char *file, unsigned int line)
63 {
64 Debug("%s[%u]: debug mode stopped", file, line);
65 if(allocations) {
66 MemoryType *mp;
67 unsigned int count = 0;
68 Debug("MEMORY: memory leaks follow");
69 for(mp = allocations; mp; mp = mp->next) {
70 Debug(" %u bytes in %s at line %u",
71 mp->size, mp->file, mp->line);
72 ++count;
73 }
74 if(count == 1) {
75 Debug("MEMORY: 1 memory leak");
76 } else {
77 Debug("MEMORY: %u memory leaks", count);
78 }
79 } else {
80 Debug("MEMORY: no memory leaks");
81 }
82 }
83
84 /** Set a checkpoint. */
DEBUG_SetCheckpoint(const char * file,unsigned int line)85 void DEBUG_SetCheckpoint(const char *file, unsigned int line)
86 {
87 checkpointFile[checkpointOffset] = file;
88 checkpointLine[checkpointOffset] = line;
89 checkpointOffset = (checkpointOffset + 1) % CHECKPOINT_LIST_SIZE;
90 }
91
92 /** Display the location of the last checkpoint. */
DEBUG_ShowCheckpoint(void)93 void DEBUG_ShowCheckpoint(void)
94 {
95 unsigned int x, offset;
96 Debug("CHECKPOINT LIST (oldest)");
97 offset = checkpointOffset;
98 for(x = 0; x < CHECKPOINT_LIST_SIZE; x++) {
99 if(checkpointFile[offset]) {
100 Debug(" %s[%u]", checkpointFile[offset], checkpointLine[offset]);
101 }
102 offset = (offset + 1) % CHECKPOINT_LIST_SIZE;
103 }
104 Debug("END OF CHECKPOINT LIST (most recent)");
105 }
106
107 /** Allocate memory and log. */
DEBUG_Allocate(size_t size,const char * file,unsigned int line)108 void *DEBUG_Allocate(size_t size, const char *file, unsigned int line)
109 {
110 MemoryType *mp;
111 mp = (MemoryType*)malloc(sizeof(MemoryType));
112 Assert(mp);
113 mp->file = file;
114 mp->line = line;
115 mp->size = size;
116 mp->pointer = malloc(size + sizeof(char) + 8);
117 if(!mp->pointer) {
118 Debug("MEMORY: %s[%u]: Memory allocation failed (%d bytes)",
119 file, line, (int)size);
120 Assert(0);
121 }
122
123 /* Make uninitialized accesses easy to find. */
124 memset(mp->pointer, 85, size);
125
126 /* Canary value for buffer underflow/overflow checking. */
127 mp->pointer[7] = 42;
128 mp->pointer[size + 8] = 42;
129
130 mp->next = allocations;
131 allocations = mp;
132 return mp->pointer + 8;
133 }
134
135 /** Reallocate memory and log. */
DEBUG_Reallocate(void * ptr,size_t size,const char * file,unsigned int line)136 void *DEBUG_Reallocate(void *ptr, size_t size,
137 const char *file,
138 unsigned int line)
139 {
140 MemoryType *mp;
141 if(!ptr) {
142 Debug("MEMORY: %s[%u]: Attempt to reallocate NULL pointer. "
143 "Calling Allocate...", file, line);
144 return DEBUG_Allocate(size, file, line);
145 } else {
146 char *cptr = (char*)ptr - 8;
147 for(mp = allocations; mp; mp = mp->next) {
148 if(mp->pointer == cptr) {
149 if(cptr[mp->size + 8] != 42) {
150 Debug("MEMORY: %s[%u]: The canary is dead (overflow).",
151 file, line);
152 }
153 if(cptr[7] != 42) {
154 Debug("MEMORY: %s[%u]: The canary is dead (underflow).",
155 file, line);
156 }
157 mp->file = file;
158 mp->line = line;
159 mp->size = size;
160 mp->pointer = realloc(cptr, size + sizeof(char) + 8);
161 if(!mp->pointer) {
162 Debug("MEMORY: %s[%u]: Failed to reallocate %d bytes.",
163 file, line, (int)size);
164 Assert(0);
165 }
166 mp->pointer[7] = 42;
167 mp->pointer[size + 8] = 42;
168 return mp->pointer + 8;
169 }
170 }
171
172 Debug("MEMORY: %s[%u]: Attempt to reallocate unallocated pointer",
173 file, line);
174 mp = malloc(sizeof(MemoryType));
175 Assert(mp);
176 mp->file = file;
177 mp->line = line;
178 mp->size = size;
179 mp->pointer = malloc(size + sizeof(char) + 8);
180 if(!mp->pointer) {
181 Debug("MEMORY: %s[%u]: Failed to reallocate %d bytes.",
182 file, line, (int)size);
183 Assert(0);
184 }
185 memset(mp->pointer, 85, size);
186 mp->pointer[7] = 42;
187 mp->pointer[size + 8] = 42;
188 mp->next = allocations;
189 allocations = mp;
190 return mp->pointer + 8;
191 }
192 }
193
194 /** Release memory and log. */
DEBUG_Release(void ** ptr,const char * file,unsigned int line)195 void DEBUG_Release(void **ptr, const char *file, unsigned int line)
196 {
197 MemoryType *mp, *last;
198 if(!ptr) {
199 Debug("MEMORY: %s[%u]: Invalid attempt to release", file, line);
200 } else if(!*ptr) {
201 Debug("MEMORY: %s[%u]: Attempt to delete NULL pointer",
202 file, line);
203 } else {
204 char *cptr = (char*)*ptr - 8;
205 last = NULL;
206 for(mp = allocations; mp; mp = mp->next) {
207 if(mp->pointer == cptr) {
208 if(last) {
209 last->next = mp->next;
210 } else {
211 allocations = mp->next;
212 }
213
214 if(cptr[mp->size + 8] != 42) {
215 Debug("MEMORY: %s[%u]: The canary is dead (overflow).",
216 file, line);
217 }
218 if(cptr[7] != 42) {
219 Debug("MEMORY: %s[%u]: The canary is dead (underflow).",
220 file, line);
221 }
222
223 memset(cptr, 0xFF, mp->size + 8 + sizeof(char));
224 free(mp);
225 free(cptr);
226 *ptr = NULL;
227 return;
228 }
229 last = mp;
230 }
231 Debug("MEMORY: %s[%u]: Attempt to delete unallocated pointer",
232 file, line);
233 free(*ptr);
234
235 /* This address should cause a segfault or bus error. */
236 *ptr = (void*)1;
237
238 }
239 }
240
241 #undef CHECKPOINT_LIST_SIZE
242
243 #endif
244
245