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