1 /*
2 * file debug.c - debugging routines
3 *
4 * $Id: debug.c,v 1.37 2006/02/18 21:40:02 fzago Exp $
5 *
6 * Program XBLAST
7 * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net)
8 *
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
11 * by the Free Software Foundation; either version 2; or (at your option)
12 * any later version
13 *
14 * This program is distributed in the hope that it will be entertaining,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17 * Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #include "xblast.h"
25
26 #ifdef DEBUG_ALLOC
27 #undef malloc
28 #undef calloc
29 #undef free
30 #endif
31
32 /*
33 * local macros
34 */
35 /* size of alloc tracking table */
36 #define TABLE_SIZE 20000
37
38 /*
39 * local types
40 */
41 /* data structure for tracking allocs */
42 typedef struct
43 {
44 const void *ptr;
45 size_t bytes;
46 const char *file;
47 int line;
48 } AllocData;
49
50 /*
51 * local variables
52 */
53 #ifdef DEBUG
54 /* start value for timer */
55 static struct timeval timeStart;
56 #endif
57
58 #ifdef DEBUG_ALLOC
59 #define USETABLE
60 #undef USETABLE
61 static int count = 0;
62 static FILE *fout = NULL;
63 static const char *outFile = NULL;
64 #ifdef USETABLE
65 static AllocData *table = NULL;
66 #endif
67 static size_t currentAlloc = 0;
68 static size_t maxAlloc = 0;
69 #endif
70
71 #if defined(DEBUG) || !defined(__GNUC__)
72 /*
73 * global function: Dbg_StartClock
74 * description: start millisec for profiling
75 */
76 void
Dbg_StartClock(void)77 Dbg_StartClock (void)
78 {
79 #ifdef DEBUG
80 gettimeofday (&timeStart, NULL);
81 #endif
82 } /* Dbg_StartClock */
83
84 /*
85 * global function: Dbg_FinishClock
86 * description: stop millisec for profiling
87 */
88 time_t
Dbg_FinishClock(void)89 Dbg_FinishClock (void)
90 {
91 #ifdef DEBUG
92 struct timeval timeEnd;
93 gettimeofday (&timeEnd, NULL);
94 return (timeEnd.tv_sec - timeStart.tv_sec) * 1000 + (timeEnd.tv_usec -
95 timeStart.tv_usec) / 1000;
96 #endif
97 } /* Dbg_FinishClock */
98
99 /*
100 * global function: Dbg_Out
101 * description: formatted debug output to stderr
102 * parameters: fmt - format string as in printf
103 * ... - variable args as in printf
104 */
105 void
Dbg_Out(const char * fmt,...)106 Dbg_Out (const char *fmt, ...)
107 {
108 #ifdef DEBUG
109 va_list argList;
110 #ifdef W32
111 static int init = 1;
112 static FILE *fp;
113 fp = stderr;
114 if (init) {
115 fp = fopen ("error.log", "w+");
116 init = 0;
117 }
118 #endif
119 va_start (argList, fmt);
120 #ifdef W32
121 vfprintf (fp, fmt, argList);
122 #else
123 vfprintf (stderr, fmt, argList);
124 #endif
125 va_end (argList);
126 #endif
127 } /* Dbg_Out */
128 #endif
129
130 /*
131 * debug outputs for certain sections
132 * for gcc: use of variadic macro to define away, use -std=c99 with -pedantic
133 * for other: use empty routines which should be optimized away
134 */
135
136 #if defined(DEBUG_CONFIG) || !defined(__GNUC__)
137 void
Dbg_Config(const char * fmt,...)138 Dbg_Config (const char *fmt, ...)
139 {
140 #ifdef DEBUG_CONFIG
141 va_list argList;
142 va_start (argList, fmt);
143 fprintf (stderr, "CONFIG: ");
144 vfprintf (stderr, fmt, argList);
145 va_end (argList);
146 #endif
147 }
148 #endif
149
150 #if defined(DEBUG_FILE) || !defined(__GNUC__)
151 void
Dbg_File(const char * fmt,...)152 Dbg_File (const char *fmt, ...)
153 {
154 #ifdef DEBUG_FILE
155 va_list argList;
156 va_start (argList, fmt);
157 fprintf (stderr, "FILE: ");
158 vfprintf (stderr, fmt, argList);
159 va_end (argList);
160 #endif
161 }
162 #endif
163
164 #if defined(DEBUG_LEVEL) || !defined(__GNUC__)
165 void
Dbg_Level(const char * fmt,...)166 Dbg_Level (const char *fmt, ...)
167 {
168 #ifdef DEBUG_LEVEL
169 va_list argList;
170 va_start (argList, fmt);
171 fprintf (stderr, "LEVEL: ");
172 vfprintf (stderr, fmt, argList);
173 va_end (argList);
174 #endif
175 }
176 #endif
177
178 #if defined(DEBUG_GAME) || !defined(__GNUC__)
179 void
Dbg_Game(const char * fmt,...)180 Dbg_Game (const char *fmt, ...)
181 {
182 #ifdef DEBUG_GAME
183 va_list argList;
184 va_start (argList, fmt);
185 fprintf (stderr, "GAME: ");
186 vfprintf (stderr, fmt, argList);
187 va_end (argList);
188 #endif
189 }
190 #endif
191
192 #if defined(DEBUG_ACTION) || !defined(__GNUC__)
193 void
Dbg_Action(const char * fmt,...)194 Dbg_Action (const char *fmt, ...)
195 {
196 #ifdef DEBUG_ACTION
197 va_list argList;
198 va_start (argList, fmt);
199 fprintf (stderr, "ACTION: ");
200 vfprintf (stderr, fmt, argList);
201 va_end (argList);
202 #endif
203 }
204 #endif
205
206 #if defined(DEBUG_NETWORK) || !defined(__GNUC__)
207 void
Dbg_Network(const char * fmt,...)208 Dbg_Network (const char *fmt, ...)
209 {
210 #ifdef DEBUG_NETWORK
211 va_list argList;
212 va_start (argList, fmt);
213 fprintf (stderr, "NETWORK: ");
214 vfprintf (stderr, fmt, argList);
215 va_end (argList);
216 #endif
217 }
218 #endif
219
220 #if defined(DEBUG_SERVER) || !defined(__GNUC__)
221 void
Dbg_Server(const char * fmt,...)222 Dbg_Server (const char *fmt, ...)
223 {
224 #ifdef DEBUG_SERVER
225 va_list argList;
226 va_start (argList, fmt);
227 fprintf (stderr, "SERVER: ");
228 vfprintf (stderr, fmt, argList);
229 va_end (argList);
230 #endif
231 }
232 #endif
233
234 #if defined(DEBUG_CLIENT) || !defined(__GNUC__)
235 void
Dbg_Client(const char * fmt,...)236 Dbg_Client (const char *fmt, ...)
237 {
238 #ifdef DEBUG_CLIENT
239 va_list argList;
240 va_start (argList, fmt);
241 fprintf (stderr, "CLIENT: ");
242 vfprintf (stderr, fmt, argList);
243 va_end (argList);
244 #endif
245 }
246 #endif
247
248 #if defined(DEBUG_USER) || !defined(__GNUC__)
249 void
Dbg_User(const char * fmt,...)250 Dbg_User (const char *fmt, ...)
251 {
252 #ifdef DEBUG_USER
253 va_list argList;
254 va_start (argList, fmt);
255 fprintf (stderr, "USER: ");
256 vfprintf (stderr, fmt, argList);
257 va_end (argList);
258 #endif
259 }
260 #endif
261
262 #if defined(DEBUG_LISTEN) || !defined(__GNUC__)
263 void
Dbg_Listen(const char * fmt,...)264 Dbg_Listen (const char *fmt, ...)
265 {
266 #ifdef DEBUG_LISTEN
267 va_list argList;
268 va_start (argList, fmt);
269 fprintf (stderr, "LISTEN: ");
270 vfprintf (stderr, fmt, argList);
271 va_end (argList);
272 #endif
273 }
274 #endif
275
276 #if defined(DEBUG_STREAM) || !defined(__GNUC__)
277 void
Dbg_Stream(const char * fmt,...)278 Dbg_Stream (const char *fmt, ...)
279 {
280 #ifdef DEBUG_STREAM
281 va_list argList;
282 va_start (argList, fmt);
283 fprintf (stderr, "STREAM: ");
284 vfprintf (stderr, fmt, argList);
285 va_end (argList);
286 #endif
287 }
288 #endif
289
290 #if defined(DEBUG_S2C) || !defined(__GNUC__)
291 void
Dbg_S2C(const char * fmt,...)292 Dbg_S2C (const char *fmt, ...)
293 {
294 #ifdef DEBUG_S2C
295 va_list argList;
296 va_start (argList, fmt);
297 fprintf (stderr, "S2C: ");
298 vfprintf (stderr, fmt, argList);
299 va_end (argList);
300 #endif
301 }
302 #endif
303
304 #if defined(DEBUG_C2S) || !defined(__GNUC__)
305 void
Dbg_C2S(const char * fmt,...)306 Dbg_C2S (const char *fmt, ...)
307 {
308 #ifdef DEBUG_C2S
309 va_list argList;
310 va_start (argList, fmt);
311 fprintf (stderr, "C2S: ");
312 vfprintf (stderr, fmt, argList);
313 va_end (argList);
314 #endif
315 }
316 #endif
317
318 #if defined(DEBUG_X2C) || !defined(__GNUC__)
319 void
Dbg_X2C(const char * fmt,...)320 Dbg_X2C (const char *fmt, ...)
321 {
322 #ifdef DEBUG_X2C
323 va_list argList;
324 va_start (argList, fmt);
325 fprintf (stderr, "X2C: ");
326 vfprintf (stderr, fmt, argList);
327 va_end (argList);
328 #endif
329 }
330 #endif
331
332 #if defined(DEBUG_C2X) || !defined(__GNUC__)
333 void
Dbg_C2X(const char * fmt,...)334 Dbg_C2X (const char *fmt, ...)
335 {
336 #ifdef DEBUG_C2X
337 va_list argList;
338 va_start (argList, fmt);
339 fprintf (stderr, "C2X: ");
340 vfprintf (stderr, fmt, argList);
341 va_end (argList);
342 #endif
343 }
344 #endif
345
346 #if defined(DEBUG_C2B) || !defined(__GNUC__)
347 void
Dbg_C2B(const char * fmt,...)348 Dbg_C2B (const char *fmt, ...)
349 {
350 #ifdef DEBUG_C2B
351 va_list argList;
352 va_start (argList, fmt);
353 fprintf (stderr, "C2B: ");
354 vfprintf (stderr, fmt, argList);
355 va_end (argList);
356 #endif
357 }
358 #endif
359
360 #if defined(DEBUG_DGRAM) || !defined(__GNUC__)
361 void
Dbg_Dgram(const char * fmt,...)362 Dbg_Dgram (const char *fmt, ...)
363 {
364 #ifdef DEBUG_DGRAM
365 va_list argList;
366 va_start (argList, fmt);
367 fprintf (stderr, "DGRAM: ");
368 vfprintf (stderr, fmt, argList);
369 va_end (argList);
370 #endif
371 }
372 #endif
373
374 #if defined(DEBUG_D2C) || !defined(__GNUC__)
375 void
Dbg_D2C(const char * fmt,...)376 Dbg_D2C (const char *fmt, ...)
377 {
378 #ifdef DEBUG_D2C
379 va_list argList;
380 va_start (argList, fmt);
381 fprintf (stderr, "D2C: ");
382 vfprintf (stderr, fmt, argList);
383 va_end (argList);
384 #endif
385 }
386 #endif
387
388 #if defined(DEBUG_D2S) || !defined(__GNUC__)
389 void
Dbg_D2S(const char * fmt,...)390 Dbg_D2S (const char *fmt, ...)
391 {
392 #ifdef DEBUG_D2S
393 va_list argList;
394 va_start (argList, fmt);
395 fprintf (stderr, "D2S: ");
396 vfprintf (stderr, fmt, argList);
397 va_end (argList);
398 #endif
399 }
400 #endif
401
402 #if defined(DEBUG_BROWSE) || !defined(__GNUC__)
403 void
Dbg_Browse(const char * fmt,...)404 Dbg_Browse (const char *fmt, ...)
405 {
406 #ifdef DEBUG_BROWSE
407 va_list argList;
408 va_start (argList, fmt);
409 fprintf (stderr, "BROWSE: ");
410 vfprintf (stderr, fmt, argList);
411 va_end (argList);
412 #endif
413 }
414 #endif
415
416 #if defined(DEBUG_NEWGAME) || !defined(__GNUC__)
417 void
Dbg_Newgame(const char * fmt,...)418 Dbg_Newgame (const char *fmt, ...)
419 {
420 #ifdef DEBUG_NEWGAME
421 va_list argList;
422 va_start (argList, fmt);
423 fprintf (stderr, "NEWGAME: ");
424 vfprintf (stderr, fmt, argList);
425 va_end (argList);
426 #endif
427 }
428 #endif
429
430 #if defined(DEBUG_REPLY) || !defined(__GNUC__)
431 void
Dbg_Reply(const char * fmt,...)432 Dbg_Reply (const char *fmt, ...)
433 {
434 #ifdef DEBUG_REPLY
435 va_list argList;
436 va_start (argList, fmt);
437 fprintf (stderr, "REPLY: ");
438 vfprintf (stderr, fmt, argList);
439 va_end (argList);
440 #endif
441 }
442 #endif
443
444 #if defined(DEBUG_QUERY) || !defined(__GNUC__)
445 void
Dbg_Query(const char * fmt,...)446 Dbg_Query (const char *fmt, ...)
447 {
448 #ifdef DEBUG_QUERY
449 va_list argList;
450 va_start (argList, fmt);
451 fprintf (stderr, "QUERY: ");
452 vfprintf (stderr, fmt, argList);
453 va_end (argList);
454 #endif
455 }
456 #endif
457
458 #if defined(DEBUG_CENTRAL) || !defined(__GNUC__)
459 void
Dbg_Central(const char * fmt,...)460 Dbg_Central (const char *fmt, ...)
461 {
462 #ifdef DEBUG_CENTRAL
463 va_list argList;
464 va_start (argList, fmt);
465 fprintf (stderr, "CENTRAL: ");
466 vfprintf (stderr, fmt, argList);
467 va_end (argList);
468 #endif
469 }
470 #endif
471
472 #if defined(DEBUG_COMM) || !defined(__GNUC__)
473 void
Dbg_Comm(const char * fmt,...)474 Dbg_Comm (const char *fmt, ...)
475 {
476 #ifdef DEBUG_COMM
477 va_list argList;
478 va_start (argList, fmt);
479 fprintf (stderr, "COMM: ");
480 vfprintf (stderr, fmt, argList);
481 va_end (argList);
482 #endif
483 }
484 #endif
485
486 #if defined(DEBUG_SOCKET) || !defined(__GNUC__)
487 void
Dbg_Socket(const char * fmt,...)488 Dbg_Socket (const char *fmt, ...)
489 {
490 #ifdef DEBUG_SOCKET
491 va_list argList;
492 va_start (argList, fmt);
493 fprintf (stderr, "SOCKET: ");
494 vfprintf (stderr, fmt, argList);
495 va_end (argList);
496 #endif
497 }
498 #endif
499
500 #if defined(DEBUG_VERSION) || !defined(__GNUC__)
501 void
Dbg_Version(const char * fmt,...)502 Dbg_Version (const char *fmt, ...)
503 {
504 #ifdef DEBUG_VERSION
505 va_list argList;
506 va_start (argList, fmt);
507 fprintf (stderr, "VERSION: ");
508 vfprintf (stderr, fmt, argList);
509 va_end (argList);
510 #endif
511 }
512 #endif
513
514 #if defined(DEBUG_CHAT) || !defined(__GNUC__)
515 void
Dbg_Chat(const char * fmt,...)516 Dbg_Chat (const char *fmt, ...)
517 {
518 #ifdef DEBUG_CHAT
519 va_list argList;
520 va_start (argList, fmt);
521 fprintf (stderr, "CHAT: ");
522 vfprintf (stderr, fmt, argList);
523 va_end (argList);
524 #endif
525 }
526 #endif
527
528 #ifdef DEBUG_ALLOC
529 /*
530 *
531 */
532 void
Dbg_FinishAlloc(void)533 Dbg_FinishAlloc (void)
534 {
535 #ifdef USETABLE
536 int i, j;
537 size_t sumBytes = 0;
538 size_t sumAlloc = 0;
539 size_t sumTotal = 0;
540 char *ptr;
541
542 for (i = 0; i < count; i++) {
543 if (table[i].ptr != NULL) {
544 fprintf (fout, "[%d] unfreed memory at 0x%08lX (%s:%d)", i, (unsigned long)table[i].ptr,
545 table[i].file, table[i].line);
546 sumAlloc++;
547 sumBytes += table[i].bytes;
548 /* output */
549 fputc ('\"', fout);
550 for (ptr = table[i].ptr, j = 0; j < table[i].bytes && j < 16; j++, ptr++) {
551 if (isprint (*ptr)) {
552 fputc (*ptr, fout);
553 }
554 else {
555 fprintf (fout, "\\%03o", (unsigned)*ptr);
556 }
557 }
558 fputs ("\"\n", fout);
559 }
560 sumTotal += table[i].bytes;
561 }
562 fprintf (stderr, "%u/%u unfree memory segments with total %u/%u/%u bytes\n", sumAlloc, count,
563 sumBytes, maxAlloc, sumTotal);
564 #else
565 fprintf (stderr, "count=%u current=%lu bytes max=%lu bytes\n", count, (unsigned long)currentAlloc, (unsigned long)maxAlloc);
566 #endif
567 } /* Finish */
568
569 /*
570 * replacement for malloc
571 */
572 void *
Dbg_Malloc(const char * file,int line,size_t nBytes)573 Dbg_Malloc (const char *file, int line, size_t nBytes)
574 {
575 void *result = malloc (nBytes);
576 #ifdef USETABLE
577 assert (count < TABLE_SIZE);
578 if (NULL == table) {
579 table = calloc (TABLE_SIZE, sizeof (*table));
580 assert (NULL != table);
581 }
582 table[count].ptr = result;
583 table[count].bytes = nBytes;
584 table[count].file = file;
585 table[count].line = line;
586 #endif
587 /* statistics */
588 currentAlloc += nBytes;
589 if (currentAlloc > maxAlloc) {
590 maxAlloc = currentAlloc;
591 }
592 /* log it */
593 if (NULL == fout) {
594 fout = (outFile == NULL) ? stderr : fopen (outFile, "w");
595 }
596 fprintf (fout, "[%d] 0x%08lX = malloc (%lu); %s:%d\n", count, (unsigned long)result,(unsigned long)nBytes,
597 file, line);
598 count++;
599 return result;
600 } /* Malloc */
601
602 /*
603 * replacement for calloc
604 */
605 void *
Dbg_Calloc(const char * file,int line,size_t nElem,size_t sElem)606 Dbg_Calloc (const char *file, int line, size_t nElem, size_t sElem)
607 {
608 void *result = calloc (nElem, sElem);
609 #ifdef USETABLE
610 assert (count < TABLE_SIZE);
611 if (NULL == table) {
612 table = calloc (TABLE_SIZE, sizeof (*table));
613 assert (NULL != table);
614 }
615 table[count].ptr = result;
616 table[count].bytes = nElem * sElem;
617 table[count].file = file;
618 table[count].line = line;
619 #endif
620 /* statistics */
621 currentAlloc += nElem * sElem;
622 if (currentAlloc > maxAlloc) {
623 maxAlloc = currentAlloc;
624 }
625 /* log it */
626 if (NULL == fout) {
627 fout = (outFile == NULL) ? stderr : fopen (outFile, "w");
628 }
629 /* hook in clean up function */
630 fprintf (fout, "[%d] 0x%08lX = calloc (%lu,%lu); %s:%d\n", count, (unsigned long)result,
631 (unsigned long)nElem, (unsigned long)sElem, file, line);
632 count++;
633 return result;
634 } /* Calloc */
635
636 /*
637 * replacement for free
638 */
639 void
Dbg_Free(const char * file,int line,void * ptr)640 Dbg_Free (const char *file, int line, void *ptr)
641 {
642 int index = 0;
643 #ifdef USETABLE
644 for (index = 0; index < count; index++) {
645 if (table[index].ptr == ptr) {
646 break;
647 }
648 }
649 table[index].ptr = NULL;
650 /* statistics */
651 currentAlloc -= table[index].bytes;
652 /* log it */
653 if (index == count) {
654 fprintf (stderr, "[?] free (0x%08lX); %s:%d\n", (unsigned long)ptr, file, line);
655 return;
656 }
657 #endif
658 if (NULL == fout) {
659 fout = (outFile == NULL) ? stderr : fopen (outFile, "w");
660 }
661 fprintf (fout, "[%d] free (0x%08lX); %s:%d\n", index, (unsigned long)ptr, file, line);
662 free (ptr);
663 } /* Free */
664
665 /*
666 * replacement for free
667 */
668 void
Dbg_Vfree(const char * file,int line,void * ptr)669 Dbg_Vfree (const char *file, int line, void *ptr)
670 {
671 int index = 0;
672 #ifdef USETABLE
673 for (index = 0; index < count; index++) {
674 if (table[index].ptr == ptr) {
675 break;
676 }
677 }
678 table[index].ptr = NULL;
679 /* statistics */
680 currentAlloc -= table[index].bytes;
681 /* log it */
682 if (index == count) {
683 fprintf (stderr, "[?] unlock (0x%08lX); %s:%d\n", (unsigned long)ptr, file, line);
684 return;
685 }
686 #endif
687 if (NULL == fout) {
688 fout = (outFile == NULL) ? stderr : fopen (outFile, "w");
689 }
690 fprintf (fout, "[%d] unlock (0x%08lX); %s:%d\n", index, (unsigned long)ptr, file, line);
691 } /* Free */
692 #endif
693
694 /*
695 * end of file alloc.
696 */
697