1a4981872799f5e3f7048abcc04c62edfce03ae2
[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 debug_level=3;
56 int segv_level=0;
57 int timestamp_prefix=0;
58
59 static int dummy;
60 static GHashTable *debug_hash;
61 static gchar *gdb_program;
62
63 static FILE *debug_fp;
64
65 #if defined(_WIN32) || defined(__CEGCC__)
66
67 static void sigsegv(int sig)
68 {
69 }
70
71 #else
72 #include <unistd.h>
73 static void sigsegv(int sig)
74 {
75         char buffer[256];
76         if (segv_level > 1)
77                 sprintf(buffer, "gdb -ex bt %s %d", gdb_program, getpid());
78         else
79                 sprintf(buffer, "gdb -ex bt -ex detach -ex quit %s %d", gdb_program, getpid());
80         system(buffer);
81         exit(1);
82 }
83 #endif
84
85 void
86 debug_init(const char *program_name)
87 {
88         gdb_program=g_strdup(program_name);
89         signal(SIGSEGV, sigsegv);
90         debug_hash=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
91 #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
92         debug_fp = stdout;
93 #else
94         debug_fp = stderr;
95 #endif
96 }
97
98
99 static void
100 debug_update_level(gpointer key, gpointer value, gpointer user_data)
101 {
102         if (debug_level < GPOINTER_TO_INT(value))
103                 debug_level = GPOINTER_TO_INT(value);
104 }
105
106 void
107 debug_level_set(const char *name, int level)
108 {
109         if (!strcmp(name, "segv")) {
110                 segv_level=level;
111                 if (segv_level)
112                         signal(SIGSEGV, sigsegv);
113                 else
114                         signal(SIGSEGV, NULL);
115         } else if (!strcmp(name, "timestamps")) {
116                 timestamp_prefix=level;
117         } else {
118                 debug_level=0;
119                 g_hash_table_insert(debug_hash, g_strdup(name), GINT_TO_POINTER(level));
120                 g_hash_table_foreach(debug_hash, debug_update_level, NULL);
121         }
122 }
123
124 struct debug *
125 debug_new(struct attr *parent, struct attr **attrs)
126 {
127         struct attr *name,*level;
128         name=attr_search(attrs, NULL, attr_name);
129         level=attr_search(attrs, NULL, attr_level);
130 #ifdef HAVE_SOCKET
131         if (!name && !level) {
132                 struct attr *socket_attr=attr_search(attrs, NULL, attr_socket);
133                 char *p,*s;
134                 if (!socket_attr)
135                         return NULL;
136                 s=g_strdup(socket_attr->u.str);
137                 p=strchr(s,':');
138                 if (!p) {
139                         g_free(s);
140                         return NULL;
141                 }
142                 *p++='\0';
143                 debug_sin.sin_family=AF_INET;
144                 if (!inet_aton(s, &debug_sin.sin_addr)) {
145                         g_free(s);
146                         return NULL;
147                 }
148                 debug_sin.sin_port=ntohs(atoi(p));
149                 if (debug_socket == -1) 
150                         debug_socket=socket(PF_INET, SOCK_DGRAM, 0);
151                 g_free(s);
152                 return (struct debug *)&dummy;  
153         }
154 #endif
155         if (!name || !level)
156                 return NULL;
157         debug_level_set(name->u.str, level->u.num);
158         return (struct debug *)&dummy;
159 }
160
161
162 int
163 debug_level_get(const char *name)
164 {
165         if (!debug_hash)
166                 return 0;
167         return GPOINTER_TO_INT(g_hash_table_lookup(debug_hash, name));
168 }
169
170 static void debug_timestamp(char *buffer)
171 {
172 #if defined HAVE_API_WIN32_CE || defined _MSC_VER
173         LARGE_INTEGER counter, frequency;
174         double val;
175         QueryPerformanceCounter(&counter);
176         QueryPerformanceFrequency(&frequency);
177         val=counter.HighPart * 4294967296.0 + counter.LowPart;
178         val/=frequency.HighPart * 4294967296.0 + frequency.LowPart;
179         sprintf(buffer,"%.6f|",val);
180
181 #else
182         struct timeval tv;
183
184         if (gettimeofday(&tv, NULL) == -1)
185                 return;
186         /* Timestamps are UTC */
187         sprintf(buffer,
188                 "%02d:%02d:%02d.%03d|",
189                 (int)(tv.tv_sec/3600)%24,
190                 (int)(tv.tv_sec/60)%60,
191                 (int)tv.tv_sec % 60,
192                 (int)tv.tv_usec/1000);
193 #endif
194 }
195
196 void
197 debug_vprintf(int level, const char *module, const int mlen, const char *function, const int flen, int prefix, const char *fmt, va_list ap)
198 {
199 #if defined HAVE_API_WIN32_CE || defined _MSC_VER
200         char buffer[4096];
201 #else
202         char buffer[mlen+flen+3];
203 #endif
204         FILE *fp=debug_fp;
205
206         sprintf(buffer, "%s:%s", module, function);
207         if (debug_level_get(module) >= level || debug_level_get(buffer) >= level) {
208 #if defined(DEBUG_WIN32_CE_MESSAGEBOX)
209                 wchar_t muni[4096];
210 #endif
211                 char xbuffer[4096];
212                 xbuffer[0]='\0';
213                 if (prefix) {
214                         if (timestamp_prefix)
215                                 debug_timestamp(xbuffer);       
216                         strcpy(xbuffer+strlen(xbuffer),buffer);
217                         strcpy(xbuffer+strlen(xbuffer),":");
218                 }
219                 vsprintf(xbuffer+strlen(xbuffer),fmt,ap);
220 #ifdef DEBUG_WIN32_CE_MESSAGEBOX
221                 mbstowcs(muni, xbuffer, strlen(xbuffer)+1);
222                 MessageBoxW(NULL, muni, TEXT("Navit - Error"), MB_APPLMODAL|MB_OK|MB_ICONERROR);
223 #else
224 #ifdef HAVE_API_ANDROID
225                 __android_log_print(ANDROID_LOG_ERROR,"navit", "%s", xbuffer);
226 #else
227 #ifdef HAVE_SOCKET
228                 if (debug_socket != -1) {
229                         sendto(debug_socket, xbuffer, strlen(xbuffer), 0, (struct sockaddr *)&debug_sin, sizeof(debug_sin));
230                         return;
231                 }
232 #endif
233                 if (! fp)
234                         fp = stderr;
235                 fprintf(fp,"%s",xbuffer);
236                 fflush(fp);
237 #endif
238 #endif
239         }
240 }
241
242 void
243 debug_printf(int level, const char *module, const int mlen,const char *function, const int flen, int prefix, const char *fmt, ...)
244 {
245         va_list ap;
246         va_start(ap, fmt);
247         debug_vprintf(level, module, mlen, function, flen, prefix, fmt, ap);
248         va_end(ap);
249 }
250
251 void
252 debug_assert_fail(const char *module, const int mlen,const char *function, const int flen, const char *file, int line, const char *expr)
253 {
254         debug_printf(0,module,mlen,function,flen,1,"%s:%d assertion failed:%s\n", file, line, expr);
255         abort();
256 }
257
258 void
259 debug_destroy(void)
260 {
261         if (!debug_fp)
262                 return;
263         if (debug_fp == stderr || debug_fp == stdout)
264                 return;
265         fclose(debug_fp);
266         debug_fp = NULL;
267 }
268
269 void debug_set_logfile(const char *path)
270 {
271         FILE *fp;
272         fp = fopen(path, "a");
273         if (fp) {
274                 debug_destroy();
275                 debug_fp = fp;
276                 fprintf(debug_fp, "Navit log started\n");
277                 fflush(debug_fp);
278         }
279 }
280
281 struct malloc_head {
282         int magic;
283         int size;
284         char *where;
285         void *return_address[8];
286         struct malloc_head *prev;
287         struct malloc_head *next;
288 } *malloc_heads;
289
290 struct malloc_tail {
291         int magic;
292 };
293
294 int mallocs,debug_malloc_size,debug_malloc_size_m;
295
296 void
297 debug_dump_mallocs(void)
298 {
299         struct malloc_head *head=malloc_heads;
300         int i;
301         dbg(0,"mallocs %d\n",mallocs);
302         while (head) {
303                 fprintf(stderr,"unfreed malloc from %s of size %d\n",head->where,head->size);
304                 for (i = 0 ; i < 8 ; i++)
305                         fprintf(stderr,"\tlist *%p\n",head->return_address[i]);
306 #if 0
307                 fprintf(stderr,"%s\n",head+1);
308 #endif
309                 head=head->next;
310         }
311 }
312
313 void *
314 debug_malloc(const char *where, int line, const char *func, int size)
315 {
316         struct malloc_head *head;
317         struct malloc_tail *tail;
318         if (!size)
319                 return NULL;
320         mallocs++;
321         debug_malloc_size+=size;
322         if (debug_malloc_size/(1024*1024) != debug_malloc_size_m) {
323                 debug_malloc_size_m=debug_malloc_size/(1024*1024);
324                 dbg(0,"malloced %d kb\n",debug_malloc_size/1024);
325         }
326         head=malloc(size+sizeof(*head)+sizeof(*tail));
327         head->magic=0xdeadbeef;
328         head->size=size;
329         head->prev=NULL;
330         head->next=malloc_heads;
331         malloc_heads=head;
332         if (head->next) 
333                 head->next->prev=head;
334         head->where=g_strdup_printf("%s:%d %s",where,line,func);
335 #if !defined (__GNUC__)
336 #define __builtin_return_address(x) NULL
337 #endif
338         head->return_address[0]=__builtin_return_address(0);
339         head->return_address[1]=__builtin_return_address(1);
340         head->return_address[2]=__builtin_return_address(2);
341         head->return_address[3]=__builtin_return_address(3);
342         head->return_address[4]=__builtin_return_address(4);
343         head->return_address[5]=__builtin_return_address(5);
344         head->return_address[6]=__builtin_return_address(6);
345         head->return_address[7]=__builtin_return_address(7);
346         head++;
347         tail=(struct malloc_tail *)((unsigned char *)head+size);
348         tail->magic=0xdeadbef0;
349         return head;
350 }
351
352
353 void *
354 debug_malloc0(const char *where, int line, const char *func, int size)
355 {
356         void *ret=debug_malloc(where, line, func, size);
357         if (ret)
358                 memset(ret, 0, size);
359         return ret;
360 }
361
362 void *
363 debug_realloc(const char *where, int line, const char *func, void *ptr, int size)
364 {
365         void *ret=debug_malloc(where, line, func, size);
366         if (ret && ptr)
367                 memcpy(ret, ptr, size);
368         debug_free(where, line, func, ptr);
369         return ret;
370 }
371
372 char *
373 debug_strdup(const char *where, int line, const char *func, const char *ptr)
374
375         int size;
376         char *ret;
377
378         if (!ptr)
379                 return NULL;
380         size=strlen(ptr)+1;
381         ret=debug_malloc(where, line, func, size);
382         memcpy(ret, ptr, size);
383         return ret;
384 }
385
386 char *
387 debug_guard(const char *where, int line, const char *func, char *str)
388 {
389         char *ret=debug_strdup(where, line, func, str);
390         g_free(str);
391         return ret;
392 }
393
394 void
395 debug_free(const char *where, int line, const char *func, void *ptr)
396 {
397         struct malloc_head *head;
398         struct malloc_tail *tail;
399         if (!ptr)
400                 return;
401         mallocs--;
402         head=(struct malloc_head *)((unsigned char *)ptr-sizeof(*head));
403         tail=(struct malloc_tail *)((unsigned char *)ptr+head->size);
404         debug_malloc_size-=head->size;
405         if (head->magic != 0xdeadbeef || tail->magic != 0xdeadbef0) {
406                 fprintf(stderr,"Invalid free from %s:%d %s\n",where,line,func);
407         }
408         head->magic=0;
409         tail->magic=0;
410         if (head->prev) 
411                 head->prev->next=head->next;
412         else
413                 malloc_heads=head->next;
414         if (head->next)
415                 head->next->prev=head->prev;
416         free(head->where);
417         free(head);
418 }
419
420 void
421 debug_free_func(void *ptr)
422 {
423         debug_free("unknown",0,"unknown",ptr);
424 }
425
426 void debug_finished(void) {
427         debug_dump_mallocs();
428         g_free(gdb_program);
429         g_hash_table_destroy(debug_hash);
430         debug_destroy();
431 }
432