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