1 /***************************************************************************
2  $RCSfile$
3                              -------------------
4     cvs         : $Id$
5     begin       : Sun Dec 04 2004
6     copyright   : (C) 2004 by Martin Preuss
7     email       : martin@libchipcard.de
8 
9  ***************************************************************************
10  *                                                                         *
11  *   This library is free software; you can redistribute it and/or         *
12  *   modify it under the terms of the GNU Lesser General Public            *
13  *   License as published by the Free Software Foundation; either          *
14  *   version 2.1 of the License, or (at your option) any later version.    *
15  *                                                                         *
16  *   This library is distributed in the hope that it will be useful,       *
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
19  *   Lesser General Public License for more details.                       *
20  *                                                                         *
21  *   You should have received a copy of the GNU Lesser General Public      *
22  *   License along with this library; if not, write to the Free Software   *
23  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston,                 *
24  *   MA  02111-1307  USA                                                   *
25  *                                                                         *
26  ***************************************************************************/
27 
28 
29 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32 
33 #include "debug_p.h"
34 
35 #include <stdarg.h>
36 #include <assert.h>
37 #include <stdio.h>
38 #ifdef HAVE_STRINGS_H
39 # include <strings.h>
40 #endif
41 #include <gwenhywfar/misc.h>
42 
43 
44 
45 static GWEN_MEMORY_DEBUG_OBJECT *gwen_debug__memobjects=0;
46 
47 
48 
GWEN_Debug_PrintDec(char * buffer,uint32_t size,uint32_t num,int leadingZero,uint32_t length)49 uint32_t GWEN_Debug_PrintDec(char *buffer,
50                              uint32_t size,
51                              uint32_t num,
52                              int leadingZero,
53                              uint32_t length)
54 {
55   uint32_t i;
56   uint32_t j;
57   uint32_t k;
58   char numbuf[16];
59   int numOr;
60 
61   /* first convert number */
62   numOr=0;
63   i=0;
64   j=1000000000;
65 
66   while (j) {
67     k=num/j;
68     numOr|=k;
69     if (numOr || leadingZero || j==1) {
70       numbuf[i]=k+'0';
71       i++;
72     }
73     num-=(k*j);
74     j/=10;
75   } /* while j */
76 
77   j=0;
78   if (length) {
79     if (i>length)
80       i=length;
81 
82     /* fill left up to length-(sizeof number) */
83     k=length-i;
84     while (k) {
85       if (j<size) {
86         if (leadingZero)
87           buffer[j]='0';
88         else
89           buffer[j]=' ';
90       }
91       j++;
92       k--;
93     } /* while k */
94   } /* if length */
95 
96   /* copy number */
97   for (k=0; k<i; k++) {
98     if (j<size)
99       buffer[j]=numbuf[k];
100     j++;
101   } /* while i */
102 
103   /* append trailing 0 */
104   if (j<size)
105     buffer[j]=0;
106   j++;
107   /* return length (or possible length) */
108   return j;
109 }
110 
111 
112 
GWEN_Debug_PrintHex(char * buffer,uint32_t size,uint32_t num,int leadingZero,int up,uint32_t length)113 uint32_t GWEN_Debug_PrintHex(char *buffer,
114                              uint32_t size,
115                              uint32_t num,
116                              int leadingZero,
117                              int up,
118                              uint32_t length)
119 {
120   uint32_t i;
121   uint32_t j;
122   uint32_t k;
123   char numbuf[16];
124   int numOr;
125 
126   /* first convert number */
127   numOr=0;
128   i=0;
129   j=8;
130 
131   while (j) {
132     k=(num>>((j-1)*4))&0xf;
133     numOr|=k;
134     if (numOr || leadingZero || j==1) {
135       if (k>9) {
136         if (up)
137           numbuf[i]=k+'0'+7;
138         else
139           numbuf[i]=k+'0'+7+32;
140       }
141       else
142         numbuf[i]=k+'0';
143       i++;
144     }
145     j--;
146   } /* while j */
147 
148   j=0;
149   if (length) {
150     if (i>length)
151       i=length;
152 
153     /* fill left up to length-(sizeof number) */
154     k=length-i;
155     while (k) {
156       if (j<size) {
157         if (leadingZero)
158           buffer[j]='0';
159         else
160           buffer[j]=' ';
161       }
162       j++;
163       k--;
164     } /* while k */
165   } /* if length */
166 
167   /* copy number */
168   for (k=0; k<i; k++) {
169     if (j<size)
170       buffer[j]=numbuf[k];
171     j++;
172   } /* while i */
173 
174   /* append trailing 0 */
175   if (j<size)
176     buffer[j]=0;
177   j++;
178   /* return length (or possible length) */
179   return j;
180 }
181 
182 
183 
184 
185 
GWEN_Debug_Snprintf(char * buffer,uint32_t size,const char * fmt,...)186 uint32_t GWEN_Debug_Snprintf(char *buffer,
187                              uint32_t size,
188                              const char *fmt, ...)
189 {
190   va_list arguments;
191   uint32_t i;
192 
193   i=0;
194   va_start(arguments, fmt);
195   while (*fmt) {
196     if (*fmt=='%') {
197       fmt++;
198       if (*fmt=='%') {
199         /* write character '%' */
200         if (i<size)
201           buffer[i]='%';
202         i++;
203       }
204       else {
205         uint32_t length;
206         int leadingZero;
207 
208         leadingZero=0;
209         length=0;
210 
211         /* read length */
212         if ((*fmt)>='0' && (*fmt)<='9') {
213           /* read number */
214           if (*fmt=='0') {
215             leadingZero=1;
216           }
217           while ((*fmt)>='0' && (*fmt)<='9') {
218             length*=10;
219             length+=*fmt-'0';
220             fmt++;
221           } /* while */
222         }
223 
224         /* read type */
225         switch (*fmt) {
226         /* decimal integer */
227         case 'c':
228         case 'd': {
229           int p;
230 
231           p=va_arg(arguments, int);
232           if (p<0) {
233             if (i<size)
234               buffer[i]='-';
235             i++;
236             p=-p;
237           }
238           i+=GWEN_Debug_PrintDec(buffer+i,
239                                  size-i,
240                                  p,
241                                  leadingZero,
242                                  length)-1;
243           break;
244         }
245 
246         /* hexadecimal integer */
247         case 'x': {
248           unsigned int p;
249 
250           p=va_arg(arguments, unsigned int);
251           i+=GWEN_Debug_PrintHex(buffer+i,
252                                  size-i,
253                                  p,
254                                  leadingZero,
255                                  0,
256                                  length)-1;
257           break;
258         }
259 
260         /* hexadecimal integer */
261         case 'X': {
262           unsigned int p;
263 
264           p=va_arg(arguments, unsigned int);
265           i+=GWEN_Debug_PrintHex(buffer+i,
266                                  size-i,
267                                  p,
268                                  leadingZero,
269                                  1,
270                                  length)-1;
271           break;
272         }
273 
274         case 's': {
275           const char *p;
276 
277           p=va_arg(arguments, const char *);
278           if (!p)
279             p="(null)";
280           while (*p) {
281             if (i<size)
282               buffer[i]=*p;
283             i++;
284             p++;
285           } /* while */
286           break;
287         }
288 
289         default:
290           break;
291         } /* switch */
292       }
293     }
294     else {
295       if (i<size)
296         buffer[i]=*fmt;
297       i++;
298     }
299     fmt++;
300   } /* while */
301 
302   /* add trailing 0 */
303   if (i<size)
304     buffer[i]=0;
305   i++;
306   va_end(arguments);
307   return i;
308 }
309 
310 
311 
312 
313 #ifdef NO_VARIADIC_MACROS
DBG_ERROR(const char * dbg_logger,const char * format,...)314 void DBG_ERROR(const char *dbg_logger, const char *format, ...)
315 {
316   va_list args;
317   char dbg_buffer[256];
318   va_start(args, format);
319   vsnprintf(dbg_buffer, sizeof(dbg_buffer)-1, format, args);
320   dbg_buffer[sizeof(dbg_buffer)-1] = 0;
321   GWEN_Logger_Log(dbg_logger, GWEN_LoggerLevelError, dbg_buffer);
322   va_end(args);
323 }
324 
DBG_WARN(const char * dbg_logger,const char * format,...)325 void DBG_WARN(const char *dbg_logger, const char *format, ...)
326 {
327   va_list args;
328   char dbg_buffer[256];
329   va_start(args, format);
330   vsnprintf(dbg_buffer, sizeof(dbg_buffer)-1, format, args);
331   dbg_buffer[sizeof(dbg_buffer)-1] = 0;
332   GWEN_Logger_Log(dbg_logger, GWEN_LoggerLevelWarning, dbg_buffer);
333   va_end(args);
334 }
335 
DBG_NOTICE(const char * dbg_logger,const char * format,...)336 void DBG_NOTICE(const char *dbg_logger, const char *format, ...)
337 {
338   if (GWEN_Logger_GetLevel(dbg_logger)>=GWEN_LoggerLevelNotice) {
339     va_list args;
340     char dbg_buffer[256];
341     va_start(args, format);
342     vsnprintf(dbg_buffer, sizeof(dbg_buffer)-1, format, args);
343     dbg_buffer[sizeof(dbg_buffer)-1] = 0;
344     GWEN_Logger_Log(dbg_logger, GWEN_LoggerLevelNotice, dbg_buffer);
345     va_end(args);
346   }
347 }
348 
DBG_INFO(const char * dbg_logger,const char * format,...)349 void DBG_INFO(const char *dbg_logger, const char *format, ...)
350 {
351   if (GWEN_Logger_GetLevel(dbg_logger)>=GWEN_LoggerLevelInfo) {
352     va_list args;
353     char dbg_buffer[256];
354     va_start(args, format);
355     vsnprintf(dbg_buffer, sizeof(dbg_buffer)-1, format, args);
356     dbg_buffer[sizeof(dbg_buffer)-1] = 0;
357     GWEN_Logger_Log(dbg_logger, GWEN_LoggerLevelInfo, dbg_buffer);
358     va_end(args);
359   }
360 }
361 
DBG_DEBUG(const char * dbg_logger,const char * format,...)362 void DBG_DEBUG(const char *dbg_logger, const char *format, ...)
363 {
364 # ifndef DISABLE_DEBUGLOG
365   if (GWEN_Logger_GetLevel(dbg_logger)>=GWEN_LoggerLevelDebug) {
366     va_list args;
367     char dbg_buffer[256];
368     va_start(args, format);
369     vsnprintf(dbg_buffer, sizeof(dbg_buffer)-1, format, args);
370     dbg_buffer[sizeof(dbg_buffer)-1] = 0;
371     GWEN_Logger_Log(dbg_logger, GWEN_LoggerLevelDebug, dbg_buffer);
372     va_end(args);
373   }
374 # endif /* DISABLE_DEBUGLOG */
375 }
376 
DBG_VERBOUS(const char * dbg_logger,const char * format,...)377 void DBG_VERBOUS(const char *dbg_logger, const char *format, ...)
378 {
379 # ifndef DISABLE_DEBUGLOG
380   if (GWEN_Logger_GetLevel(dbg_logger)>=GWEN_LoggerLevelVerbous) {
381     va_list args;
382     char dbg_buffer[256];
383     va_start(args, format);
384     vsnprintf(dbg_buffer, sizeof(dbg_buffer)-1, format, args);
385     dbg_buffer[sizeof(dbg_buffer)-1] = 0;
386     GWEN_Logger_Log(dbg_logger, GWEN_LoggerLevelVerbous, dbg_buffer);
387     va_end(args);
388   }
389 # endif /* DISABLE_DEBUGLOG */
390 }
391 
392 #endif /* NO_VARIADIC_MACROS */
393 
394 
395 
396 
397 
398 
399 
GWEN_MemoryDebugEntry_new(GWEN_MEMORY_DEBUG_ENTRY_TYPE t,const char * wFile,int wLine)400 GWEN_MEMORY_DEBUG_ENTRY *GWEN_MemoryDebugEntry_new(GWEN_MEMORY_DEBUG_ENTRY_TYPE t,
401                                                    const char *wFile,
402                                                    int wLine)
403 {
404   GWEN_MEMORY_DEBUG_ENTRY *e;
405 
406   assert(wFile);
407   assert(wLine);
408   GWEN_NEW_OBJECT(GWEN_MEMORY_DEBUG_ENTRY, e);
409   e->file=strdup(wFile);
410   e->line=wLine;
411   e->type=t;
412   return e;
413 }
414 
415 
416 
GWEN_MemoryDebugEntry_free(GWEN_MEMORY_DEBUG_ENTRY * e)417 void GWEN_MemoryDebugEntry_free(GWEN_MEMORY_DEBUG_ENTRY *e)
418 {
419   if (e) {
420     free(e->file);
421     GWEN_FREE_OBJECT(e);
422   }
423 }
424 
425 
426 
427 
GWEN_MemoryDebugObject_new(const char * name)428 GWEN_MEMORY_DEBUG_OBJECT *GWEN_MemoryDebugObject_new(const char *name)
429 {
430   GWEN_MEMORY_DEBUG_OBJECT *o;
431 
432   assert(name);
433   GWEN_NEW_OBJECT(GWEN_MEMORY_DEBUG_OBJECT, o);
434   o->name=strdup(name);
435   return o;
436 }
437 
438 
439 
GWEN_MemoryDebugObject_free(GWEN_MEMORY_DEBUG_OBJECT * o)440 void GWEN_MemoryDebugObject_free(GWEN_MEMORY_DEBUG_OBJECT *o)
441 {
442   if (o) {
443     GWEN_MEMORY_DEBUG_ENTRY *e;
444 
445     e=o->entries;
446     while (e) {
447       GWEN_MEMORY_DEBUG_ENTRY *next;
448 
449       next=e->next;
450       GWEN_MemoryDebugEntry_free(e);
451       e=next;
452     }
453     free(o->name);
454     GWEN_FREE_OBJECT(o);
455   }
456 }
457 
458 
459 
GWEN_MemoryDebug__FindObject(const char * name)460 GWEN_MEMORY_DEBUG_OBJECT *GWEN_MemoryDebug__FindObject(const char *name)
461 {
462   GWEN_MEMORY_DEBUG_OBJECT *o;
463 
464   o=gwen_debug__memobjects;
465   while (o) {
466     assert(o->name);
467     if (strcasecmp(o->name, name)==0)
468       break;
469     if (o->next==o) {
470       DBG_ERROR(GWEN_LOGDOMAIN, "What ?? Pointing to myself ??");
471       abort();
472     }
473     o=o->next;
474   }
475 
476   return o;
477 }
478 
479 
480 
GWEN_MemoryDebug_Increment(const char * name,const char * wFile,int wLine,int attach)481 void GWEN_MemoryDebug_Increment(const char *name,
482                                 const char *wFile,
483                                 int wLine,
484                                 int attach)
485 {
486   GWEN_MEMORY_DEBUG_OBJECT *o;
487   GWEN_MEMORY_DEBUG_ENTRY *e;
488 
489   assert(name);
490   assert(wFile);
491   assert(wLine);
492   o=GWEN_MemoryDebug__FindObject(name);
493   if (!o) {
494     o=GWEN_MemoryDebugObject_new(name);
495     GWEN_LIST_ADD(GWEN_MEMORY_DEBUG_OBJECT, o, &gwen_debug__memobjects);
496     e=GWEN_MemoryDebugEntry_new(attach?GWEN_MemoryDebugEntryTypeAttach:
497                                 GWEN_MemoryDebugEntryTypeCreate,
498                                 wFile, wLine);
499     GWEN_LIST_ADD(GWEN_MEMORY_DEBUG_ENTRY, e, &(o->entries));
500     o->count++;
501   }
502   else {
503     e=GWEN_MemoryDebugEntry_new(attach?GWEN_MemoryDebugEntryTypeAttach:
504                                 GWEN_MemoryDebugEntryTypeCreate,
505                                 wFile, wLine);
506     GWEN_LIST_ADD(GWEN_MEMORY_DEBUG_ENTRY, e, &(o->entries));
507     o->count++;
508   }
509 }
510 
511 
512 
GWEN_MemoryDebug_Decrement(const char * name,const char * wFile,int wLine)513 void GWEN_MemoryDebug_Decrement(const char *name,
514                                 const char *wFile,
515                                 int wLine)
516 {
517   GWEN_MEMORY_DEBUG_OBJECT *o;
518   GWEN_MEMORY_DEBUG_ENTRY *e;
519 
520   assert(name);
521   assert(wFile);
522   assert(wLine);
523   o=GWEN_MemoryDebug__FindObject(name);
524   if (!o) {
525     DBG_ERROR(GWEN_LOGDOMAIN,
526               "Object to be freed not found (%s at %s:%d)",
527               name, wFile, wLine);
528     o=GWEN_MemoryDebugObject_new(name);
529     GWEN_LIST_ADD(GWEN_MEMORY_DEBUG_OBJECT, o, &gwen_debug__memobjects);
530     e=GWEN_MemoryDebugEntry_new(GWEN_MemoryDebugEntryTypeFree,
531                                 wFile, wLine);
532     GWEN_LIST_ADD(GWEN_MEMORY_DEBUG_ENTRY, e, &(o->entries));
533     o->count--;
534   }
535   else {
536     e=GWEN_MemoryDebugEntry_new(GWEN_MemoryDebugEntryTypeFree,
537                                 wFile, wLine);
538     GWEN_LIST_ADD(GWEN_MEMORY_DEBUG_ENTRY, e, &(o->entries));
539     o->count--;
540   }
541 }
542 
543 
544 
GWEN_MemoryDebug__DumpObject(GWEN_MEMORY_DEBUG_OBJECT * o,uint32_t mode)545 void GWEN_MemoryDebug__DumpObject(GWEN_MEMORY_DEBUG_OBJECT *o,
546                                   uint32_t mode)
547 {
548 
549   DBG_ERROR(0, "Object \"%s\" (count=%ld)",
550             o->name, o->count);
551   if (o->count!=0 || mode==GWEN_MEMORY_DEBUG_MODE_DETAILED) {
552     GWEN_MEMORY_DEBUG_ENTRY *e;
553 
554     if (mode!=GWEN_MEMORY_DEBUG_MODE_SHORT) {
555       e=o->entries;
556       while (e) {
557         const char *s;
558 
559         fprintf(stderr, " ");
560         switch (e->type) {
561         case GWEN_MemoryDebugEntryTypeCreate:
562           s="created";
563           break;
564         case GWEN_MemoryDebugEntryTypeAttach:
565           s="attached";
566           break;
567         case GWEN_MemoryDebugEntryTypeFree:
568           s="freed";
569           break;
570         case GWEN_MemoryDebugEntryTypeUnknown:
571         default:
572           s="<unknown action>";
573           break;
574         }
575         DBG_ERROR(0, " %s at %s:%d", s, e->file, e->line);
576         e=e->next;
577       } /* while e */
578     }
579   }
580 }
581 
582 
583 
GWEN_MemoryDebug_DumpObject(const char * name,uint32_t mode)584 void GWEN_MemoryDebug_DumpObject(const char *name,
585                                  uint32_t mode)
586 {
587   GWEN_MEMORY_DEBUG_OBJECT *o;
588 
589   assert(name);
590   o=GWEN_MemoryDebug__FindObject(name);
591   if (!o) {
592     DBG_ERROR(GWEN_LOGDOMAIN, "Object \"%s\" not found", name);
593   }
594   else
595     GWEN_MemoryDebug__DumpObject(o, mode);
596 }
597 
598 
599 
GWEN_MemoryDebug_GetObjectCount(const char * name)600 long int GWEN_MemoryDebug_GetObjectCount(const char *name)
601 {
602   GWEN_MEMORY_DEBUG_OBJECT *o;
603 
604   assert(name);
605   o=GWEN_MemoryDebug__FindObject(name);
606   if (!o) {
607     DBG_ERROR(GWEN_LOGDOMAIN, "Object \"%s\" not found", name);
608     return 0;
609   }
610   else
611     return o->count;
612 }
613 
614 
615 
GWEN_MemoryDebug_Dump(uint32_t mode)616 void GWEN_MemoryDebug_Dump(uint32_t mode)
617 {
618   GWEN_MEMORY_DEBUG_OBJECT *o;
619 
620   DBG_ERROR(0, "Gwenhywfar Memory Debugger Statistics:");
621   DBG_ERROR(0, "====================================== begin\n");
622   o=gwen_debug__memobjects;
623   while (o) {
624     GWEN_MemoryDebug__DumpObject(o, mode);
625     o=o->next;
626   }
627   DBG_ERROR(0, "====================================== end\n");
628 }
629 
630 
631 
GWEN_MemoryDebug_CleanUp(void)632 void GWEN_MemoryDebug_CleanUp(void)
633 {
634   GWEN_MEMORY_DEBUG_OBJECT *o;
635 
636   o=gwen_debug__memobjects;
637   while (o) {
638     GWEN_MEMORY_DEBUG_OBJECT *next;
639 
640     next=o->next;
641     GWEN_MemoryDebugObject_free(o);
642     o=next;
643   }
644   gwen_debug__memobjects=0;
645 }
646 
647 
648 
649 
650