Add:Core:New "global" debug level; activate option -d.
[profile/ivi/navit.git] / navit / navit / debug.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #include <signal.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <glib.h>
27 #ifndef _MSC_VER
28 #include <sys/time.h>
29 #endif /* _MSC_VER */
30 #include "config.h"
31 #include "file.h"
32 #include "item.h"
33 #include "debug.h"
34
35 #ifdef HAVE_API_ANDROID
36 #include <android/log.h>
37 #endif
38
39 #if defined HAVE_API_WIN32_CE || defined _MSC_VER
40 #include <windows.h>
41 #include <windowsx.h>
42 #endif
43
44 #ifdef HAVE_SOCKET
45 #include <stdlib.h>
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
49
50 static int debug_socket=-1;
51 static struct sockaddr_in debug_sin;
52 #endif
53
54
55 int max_debug_level=0;
56 int global_debug_level=0;
57 int segv_level=0;
58 int timestamp_prefix=0;
59
60 static int dummy;
61 static GHashTable *debug_hash;
62 static gchar *gdb_program;
63
64 static FILE *debug_fp;
65
66 #if defined(_WIN32) || defined(__CEGCC__)
67
68 static void sigsegv(int sig)
69 {
70 }
71
72 #else
73 #include <unistd.h>
74 static void sigsegv(int sig)
75 {
76         char buffer[256];
77         if (segv_level > 1)
78                 sprintf(buffer, "gdb -ex bt %s %d", gdb_program, getpid());
79         else
80                 sprintf(buffer, "gdb -ex bt -ex detach -ex quit %s %d", gdb_program, getpid());
81         system(buffer);
82         exit(1);
83 }
84 #endif
85
86 void
87 debug_init(const char *program_name)
88 {
89         gdb_program=g_strdup(program_name);
90         signal(SIGSEGV, sigsegv);
91         debug_hash=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
92 #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
93         debug_fp = stdout;
94 #else
95         debug_fp = stderr;
96 #endif
97 }
98
99
100 static void
101 debug_update_level(gpointer key, gpointer value, gpointer user_data)
102 {
103         if (max_debug_level < GPOINTER_TO_INT(value))
104                 max_debug_level = GPOINTER_TO_INT(value);
105 }
106
107 void
108 debug_level_set(const char *name, int level)
109 {
110         if (!strcmp(name, "segv")) {
111                 segv_level=level;
112                 if (segv_level)
113                         signal(SIGSEGV, sigsegv);
114                 else
115                         signal(SIGSEGV, NULL);
116         } else if (!strcmp(name, "timestamps")) {
117                 timestamp_prefix=level;
118         } else if (!strcmp(name, DEBUG_MODULE_GLOBAL)) {
119                 global_debug_level=level;
120                 if (max_debug_level < global_debug_level){
121                         max_debug_level = global_debug_level;
122                 }
123         } else {
124                 g_hash_table_insert(debug_hash, g_strdup(name), GINT_TO_POINTER(level));
125                 g_hash_table_foreach(debug_hash, debug_update_level, NULL);
126         }
127 }
128
129 struct debug *
130 debug_new(struct attr *parent, struct attr **attrs)
131 {
132         struct attr *name,*level;
133         name=attr_search(attrs, NULL, attr_name);
134         level=attr_search(attrs, NULL, attr_level);
135 #ifdef HAVE_SOCKET
136         if (!name && !level) {
137                 struct attr *socket_attr=attr_search(attrs, NULL, attr_socket);
138                 char *p,*s;
139                 if (!socket_attr)
140                         return NULL;
141                 s=g_strdup(socket_attr->u.str);
142                 p=strchr(s,':');
143                 if (!p) {
144                         g_free(s);
145                         return NULL;
146                 }
147                 *p++='\0';
148                 debug_sin.sin_family=AF_INET;
149                 if (!inet_aton(s, &debug_sin.sin_addr)) {
150                         g_free(s);
151                         return NULL;
152                 }
153                 debug_sin.sin_port=ntohs(atoi(p));
154                 if (debug_socket == -1) 
155                         debug_socket=socket(PF_INET, SOCK_DGRAM, 0);
156                 g_free(s);
157                 return (struct debug *)&dummy;  
158         }
159 #endif
160         if (!name || !level)
161                 return NULL;
162         debug_level_set(name->u.str, level->u.num);
163         return (struct debug *)&dummy;
164 }
165
166
167 int
168 debug_level_get(const char *name)
169 {
170         if (!debug_hash)
171                 return 0;
172         return GPOINTER_TO_INT(g_hash_table_lookup(debug_hash, name));
173 }
174
175 static void debug_timestamp(char *buffer)
176 {
177 #if defined HAVE_API_WIN32_CE || defined _MSC_VER
178         LARGE_INTEGER counter, frequency;
179         double val;
180         QueryPerformanceCounter(&counter);
181         QueryPerformanceFrequency(&frequency);
182         val=counter.HighPart * 4294967296.0 + counter.LowPart;
183         val/=frequency.HighPart * 4294967296.0 + frequency.LowPart;
184         sprintf(buffer,"%.6f|",val);
185
186 #else
187         struct timeval tv;
188
189         if (gettimeofday(&tv, NULL) == -1)
190                 return;
191         /* Timestamps are UTC */
192         sprintf(buffer,
193                 "%02d:%02d:%02d.%03d|",
194                 (int)(tv.tv_sec/3600)%24,
195                 (int)(tv.tv_sec/60)%60,
196                 (int)tv.tv_sec % 60,
197                 (int)tv.tv_usec/1000);
198 #endif
199 }
200
201 void
202 debug_vprintf(int level, const char *module, const int mlen, const char *function, const int flen, int prefix, const char *fmt, va_list ap)
203 {
204 #if defined HAVE_API_WIN32_CE || defined _MSC_VER
205         char buffer[4096];
206 #else
207         char buffer[mlen+flen+3];
208 #endif
209         FILE *fp=debug_fp;
210
211         sprintf(buffer, "%s:%s", module, function);
212         if (global_debug_level >= level || debug_level_get(module) >= level || debug_level_get(buffer) >= level) {
213 #if defined(DEBUG_WIN32_CE_MESSAGEBOX)
214                 wchar_t muni[4096];
215 #endif
216                 char xbuffer[4096];
217                 xbuffer[0]='\0';
218                 if (prefix) {
219                         if (timestamp_prefix)
220                                 debug_timestamp(xbuffer);       
221                         strcpy(xbuffer+strlen(xbuffer),buffer);
222                         strcpy(xbuffer+strlen(xbuffer),":");
223                 }
224                 vsprintf(xbuffer+strlen(xbuffer),fmt,ap);
225 #ifdef DEBUG_WIN32_CE_MESSAGEBOX
226                 mbstowcs(muni, xbuffer, strlen(xbuffer)+1);
227                 MessageBoxW(NULL, muni, TEXT("Navit - Error"), MB_APPLMODAL|MB_OK|MB_ICONERROR);
228 #else
229 #ifdef HAVE_API_ANDROID
230                 __android_log_print(ANDROID_LOG_ERROR,"navit", "%s", xbuffer);
231 #else
232 #ifdef HAVE_SOCKET
233                 if (debug_socket != -1) {
234                         sendto(debug_socket, xbuffer, strlen(xbuffer), 0, (struct sockaddr *)&debug_sin, sizeof(debug_sin));
235                         return;
236                 }
237 #endif
238                 if (! fp)
239                         fp = stderr;
240                 fprintf(fp,"%s",xbuffer);
241                 fflush(fp);
242 #endif
243 #endif
244         }
245 }
246
247 void
248 debug_printf(int level, const char *module, const int mlen,const char *function, const int flen, int prefix, const char *fmt, ...)
249 {
250         va_list ap;
251         va_start(ap, fmt);
252         debug_vprintf(level, module, mlen, function, flen, prefix, fmt, ap);
253         va_end(ap);
254 }
255
256 void
257 debug_assert_fail(const char *module, const int mlen,const char *function, const int flen, const char *file, int line, const char *expr)
258 {
259         debug_printf(0,module,mlen,function,flen,1,"%s:%d assertion failed:%s\n", file, line, expr);
260         abort();
261 }
262
263 void
264 debug_destroy(void)
265 {
266         if (!debug_fp)
267                 return;
268         if (debug_fp == stderr || debug_fp == stdout)
269                 return;
270         fclose(debug_fp);
271         debug_fp = NULL;
272 }
273
274 void debug_set_logfile(const char *path)
275 {
276         FILE *fp;
277         fp = fopen(path, "a");
278         if (fp) {
279                 debug_destroy();
280                 debug_fp = fp;
281                 fprintf(debug_fp, "Navit log started\n");
282                 fflush(debug_fp);
283         }
284 }
285
286 struct malloc_head {
287         int magic;
288         int size;
289         char *where;
290         void *return_address[8];
291         struct malloc_head *prev;
292         struct malloc_head *next;
293 } *malloc_heads;
294
295 struct malloc_tail {
296         int magic;
297 };
298
299 int mallocs,debug_malloc_size,debug_malloc_size_m;
300
301 void
302 debug_dump_mallocs(void)
303 {
304         struct malloc_head *head=malloc_heads;
305         int i;
306         dbg(0,"mallocs %d\n",mallocs);
307         while (head) {
308                 fprintf(stderr,"unfreed malloc from %s of size %d\n",head->where,head->size);
309                 for (i = 0 ; i < 8 ; i++)
310                         fprintf(stderr,"\tlist *%p\n",head->return_address[i]);
311 #if 0
312                 fprintf(stderr,"%s\n",head+1);
313 #endif
314                 head=head->next;
315         }
316 }
317
318 void *
319 debug_malloc(const char *where, int line, const char *func, int size)
320 {
321         struct malloc_head *head;
322         struct malloc_tail *tail;
323         if (!size)
324                 return NULL;
325         mallocs++;
326         debug_malloc_size+=size;
327         if (debug_malloc_size/(1024*1024) != debug_malloc_size_m) {
328                 debug_malloc_size_m=debug_malloc_size/(1024*1024);
329                 dbg(0,"malloced %d kb\n",debug_malloc_size/1024);
330         }
331         head=malloc(size+sizeof(*head)+sizeof(*tail));
332         head->magic=0xdeadbeef;
333         head->size=size;
334         head->prev=NULL;
335         head->next=malloc_heads;
336         malloc_heads=head;
337         if (head->next) 
338                 head->next->prev=head;
339         head->where=g_strdup_printf("%s:%d %s",where,line,func);
340 #if !defined (__GNUC__)
341 #define __builtin_return_address(x) NULL
342 #endif
343         head->return_address[0]=__builtin_return_address(0);
344         head->return_address[1]=__builtin_return_address(1);
345         head->return_address[2]=__builtin_return_address(2);
346         head->return_address[3]=__builtin_return_address(3);
347         head->return_address[4]=__builtin_return_address(4);
348         head->return_address[5]=__builtin_return_address(5);
349         head->return_address[6]=__builtin_return_address(6);
350         head->return_address[7]=__builtin_return_address(7);
351         head++;
352         tail=(struct malloc_tail *)((unsigned char *)head+size);
353         tail->magic=0xdeadbef0;
354         return head;
355 }
356
357
358 void *
359 debug_malloc0(const char *where, int line, const char *func, int size)
360 {
361         void *ret=debug_malloc(where, line, func, size);
362         if (ret)
363                 memset(ret, 0, size);
364         return ret;
365 }
366
367 void *
368 debug_realloc(const char *where, int line, const char *func, void *ptr, int size)
369 {
370         void *ret=debug_malloc(where, line, func, size);
371         if (ret && ptr)
372                 memcpy(ret, ptr, size);
373         debug_free(where, line, func, ptr);
374         return ret;
375 }
376
377 char *
378 debug_strdup(const char *where, int line, const char *func, const char *ptr)
379
380         int size;
381         char *ret;
382
383         if (!ptr)
384                 return NULL;
385         size=strlen(ptr)+1;
386         ret=debug_malloc(where, line, func, size);
387         memcpy(ret, ptr, size);
388         return ret;
389 }
390
391 char *
392 debug_guard(const char *where, int line, const char *func, char *str)
393 {
394         char *ret=debug_strdup(where, line, func, str);
395         g_free(str);
396         return ret;
397 }
398
399 void
400 debug_free(const char *where, int line, const char *func, void *ptr)
401 {
402         struct malloc_head *head;
403         struct malloc_tail *tail;
404         if (!ptr)
405                 return;
406         mallocs--;
407         head=(struct malloc_head *)((unsigned char *)ptr-sizeof(*head));
408         tail=(struct malloc_tail *)((unsigned char *)ptr+head->size);
409         debug_malloc_size-=head->size;
410         if (head->magic != 0xdeadbeef || tail->magic != 0xdeadbef0) {
411                 fprintf(stderr,"Invalid free from %s:%d %s\n",where,line,func);
412         }
413         head->magic=0;
414         tail->magic=0;
415         if (head->prev) 
416                 head->prev->next=head->next;
417         else
418                 malloc_heads=head->next;
419         if (head->next)
420                 head->next->prev=head->prev;
421         free(head->where);
422         free(head);
423 }
424
425 void
426 debug_free_func(void *ptr)
427 {
428         debug_free("unknown",0,"unknown",ptr);
429 }
430
431 void debug_finished(void) {
432         debug_dump_mallocs();
433         g_free(gdb_program);
434         g_hash_table_destroy(debug_hash);
435         debug_destroy();
436 }
437