/* * file debug.c - debugging routines * * $Id: debug.c,v 1.4 2004/06/26 03:23:18 iskywalker Exp $ * * Program XBLAST * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2; or (at your option) * any later version * * This program is distributed in the hope that it will be entertaining, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "debug.h" #ifdef WMS #include "timeval.h" #endif #ifdef DEBUG_ALLOC #undef malloc #undef calloc #undef free #endif /* * local macros */ /* size of alloc tracking table */ #define TABLE_SIZE 20000 /* * local types */ /* data structure for tracking allocs */ typedef struct { const void *ptr; size_t bytes; const char *file; int line; } AllocData; /* * local variables */ #ifdef DEBUG /* start value for timer */ static struct timeval timeStart; #endif #ifdef DEBUG_ALLOC static int count = 0; static FILE *fout = NULL; static const char *outFile = "alloc.txt"; static AllocData *table = NULL; static size_t currentAlloc = 0; static size_t maxAlloc = 0; #endif #ifdef DEBUG /* * global function: Dbg_StartClock * description: start millisec for profiling */ void Dbg_StartClock (void) { gettimeofday (&timeStart, NULL); } /* Dbg_StartClock */ /* * global function: Dbg_FinishClock * description: stop millisec for profiling */ time_t Dbg_FinishClock (void) { struct timeval timeEnd; gettimeofday (&timeEnd, NULL); return (timeEnd.tv_sec - timeStart.tv_sec) * 1000 + (timeEnd.tv_usec - timeStart.tv_usec) / 1000; } /* Dbg_FinishClock */ /* * global function: Dbg_Out * description: formatted debug output to stderr * parameters: fmt - format string as in printf * ... - variable args as in printf */ void Dbg_Out (const char *fmt, ...) { va_list argList; va_start (argList, fmt); vfprintf (stderr, fmt, argList); va_end (argList); } /* Dgb_Out */ #endif #ifdef DEBUG_ALLOC /* * */ void Dbg_FinishAlloc (void) { int i, j; size_t sumBytes = 0; size_t sumAlloc = 0; size_t sumTotal = 0; char *ptr; for (i = 0; i < count; i ++) { if (table[i].ptr != NULL) { fprintf (fout, "[%d] unfreed memory at 0x%08lX (%s:%d)", i, (unsigned long) table[i].ptr, table[i].file, table[i].line); sumAlloc ++; sumBytes += table[i].bytes; /* output */ fputc ('\"', fout); for (ptr = table[i].ptr, j = 0; j < table[i].bytes && j < 16; j ++, ptr ++) { if (isprint (*ptr)) { fputc (*ptr, fout); } else { fprintf (fout, "\\%03o", (unsigned) *ptr); } } fputs ("\"\n", fout); } sumTotal += table[i].bytes; } fprintf (stderr, "%u/%u unfree memory segments with total %u/%u/%u bytes\n", sumAlloc, count, sumBytes, maxAlloc, sumTotal); } /* Finish */ /* * replacement for malloc */ void * Dbg_Malloc (const char *file, int line, size_t nBytes) { void *result = malloc (nBytes); assert (count < TABLE_SIZE); if (NULL == table) { table = calloc (TABLE_SIZE, sizeof (*table)); assert (NULL != table); } table[count].ptr = result; table[count].bytes = nBytes; table[count].file = file; table[count].line = line; /* statistics */ currentAlloc += nBytes; if (currentAlloc > maxAlloc) { maxAlloc = currentAlloc; } /* log it */ if (NULL == fout) { fout = fopen (outFile, "w"); } fprintf (fout, "[%d] 0x%08lX = malloc (%u); %s:%d\n", count, (unsigned long) result, nBytes, file, line); count ++; return result; } /* Malloc */ /* * replacement for calloc */ void * Dbg_Calloc (const char *file, int line, size_t nElem, size_t sElem) { void *result = calloc (nElem, sElem); assert (count < TABLE_SIZE); if (NULL == table) { table = calloc (TABLE_SIZE, sizeof (*table)); assert (NULL != table); } table[count].ptr = result; table[count].bytes = nElem * sElem; table[count].file = file; table[count].line = line; /* statistics */ currentAlloc += nElem * sElem; if (currentAlloc > maxAlloc) { maxAlloc = currentAlloc; } /* log it */ if (NULL == fout) { fout = fopen (outFile, "w"); } /* hook in clean up function */ fprintf (fout, "[%d] 0x%08lX = calloc (%u,%u); %s:%d\n", count, (unsigned long) result, nElem, sElem, file, line); count ++; return result; } /* Calloc */ /* * replacement for free */ void Dbg_Free (const char *file, int line, void *ptr) { int index; for (index = 0; index < count; index ++) { if (table[index].ptr == ptr) { break; } } table[index].ptr = NULL; /* statistics */ currentAlloc -= table[index].bytes; /* log it */ if (index == count) { fprintf (stderr, "[?] free (0x%08lX); %s:%d\n", (unsigned long) ptr, file, line); return; } if (NULL == fout) { fout = fopen (outFile, "w"); } fprintf (fout, "[%d] free (0x%08lX); %s:%d\n", index, (unsigned long) ptr, file, line); free (ptr); } /* Free */ /* * replacement for free */ void Dbg_Vfree (const char *file, int line, void *ptr) { int index; for (index = 0; index < count; index ++) { if (table[index].ptr == ptr) { break; } } table[index].ptr = NULL; /* statistics */ currentAlloc -= table[index].bytes; /* log it */ if (index == count) { fprintf (stderr, "[?] unlock (0x%08lX); %s:%d\n", (unsigned long) ptr, file, line); return; } if (NULL == fout) { fout = fopen (outFile, "w"); } fprintf (fout, "[%d] unlock (0x%08lX); %s:%d\n", index, (unsigned long) ptr, file, line); } /* Free */ #endif /* * end of file alloc. */