2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2008 Navit Team
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.
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.
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.
35 #ifdef HAVE_API_ANDROID
36 #include <android/log.h>
39 #if defined HAVE_API_WIN32_CE || defined _MSC_VER
46 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
50 static int debug_socket=-1;
51 static struct sockaddr_in debug_sin;
57 int timestamp_prefix=0;
60 static GHashTable *debug_hash;
61 static gchar *gdb_program;
63 static FILE *debug_fp;
65 #if defined(_WIN32) || defined(__CEGCC__)
67 static void sigsegv(int sig)
73 static void sigsegv(int sig)
77 sprintf(buffer, "gdb -ex bt %s %d", gdb_program, getpid());
79 sprintf(buffer, "gdb -ex bt -ex detach -ex quit %s %d", gdb_program, getpid());
86 debug_init(const char *program_name)
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
100 debug_update_level(gpointer key, gpointer value, gpointer user_data)
102 if (debug_level < GPOINTER_TO_INT(value))
103 debug_level = GPOINTER_TO_INT(value);
107 debug_level_set(const char *name, int level)
109 if (!strcmp(name, "segv")) {
112 signal(SIGSEGV, sigsegv);
114 signal(SIGSEGV, NULL);
115 } else if (!strcmp(name, "timestamps")) {
116 timestamp_prefix=level;
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);
125 debug_new(struct attr *parent, struct attr **attrs)
127 struct attr *name,*level;
128 name=attr_search(attrs, NULL, attr_name);
129 level=attr_search(attrs, NULL, attr_level);
131 if (!name && !level) {
132 struct attr *socket_attr=attr_search(attrs, NULL, attr_socket);
136 s=g_strdup(socket_attr->u.str);
143 debug_sin.sin_family=AF_INET;
144 if (!inet_aton(s, &debug_sin.sin_addr)) {
148 debug_sin.sin_port=ntohs(atoi(p));
149 if (debug_socket == -1)
150 debug_socket=socket(PF_INET, SOCK_DGRAM, 0);
152 return (struct debug *)&dummy;
157 debug_level_set(name->u.str, level->u.num);
158 return (struct debug *)&dummy;
163 debug_level_get(const char *name)
167 return GPOINTER_TO_INT(g_hash_table_lookup(debug_hash, name));
170 static void debug_timestamp(char *buffer)
172 #if defined HAVE_API_WIN32_CE || defined _MSC_VER
173 LARGE_INTEGER counter, frequency;
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);
184 if (gettimeofday(&tv, NULL) == -1)
186 /* Timestamps are UTC */
188 "%02d:%02d:%02d.%03d|",
189 (int)(tv.tv_sec/3600)%24,
190 (int)(tv.tv_sec/60)%60,
192 (int)tv.tv_usec/1000);
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)
199 #if defined HAVE_API_WIN32_CE || defined _MSC_VER
202 char buffer[mlen+flen+3];
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)
214 if (timestamp_prefix)
215 debug_timestamp(xbuffer);
216 strcpy(xbuffer+strlen(xbuffer),buffer);
217 strcpy(xbuffer+strlen(xbuffer),":");
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);
224 #ifdef HAVE_API_ANDROID
225 __android_log_print(ANDROID_LOG_ERROR,"navit", "%s", xbuffer);
228 if (debug_socket != -1) {
229 sendto(debug_socket, xbuffer, strlen(xbuffer), 0, (struct sockaddr *)&debug_sin, sizeof(debug_sin));
235 fprintf(fp,"%s",xbuffer);
243 debug_printf(int level, const char *module, const int mlen,const char *function, const int flen, int prefix, const char *fmt, ...)
247 debug_vprintf(level, module, mlen, function, flen, prefix, fmt, ap);
252 debug_assert_fail(const char *module, const int mlen,const char *function, const int flen, const char *file, int line, const char *expr)
254 debug_printf(0,module,mlen,function,flen,1,"%s:%d assertion failed:%s\n", file, line, expr);
263 if (debug_fp == stderr || debug_fp == stdout)
269 void debug_set_logfile(const char *path)
272 fp = fopen(path, "a");
276 fprintf(debug_fp, "Navit log started\n");
285 void *return_address[8];
286 struct malloc_head *prev;
287 struct malloc_head *next;
294 int mallocs,debug_malloc_size,debug_malloc_size_m;
297 debug_dump_mallocs(void)
299 struct malloc_head *head=malloc_heads;
301 dbg(0,"mallocs %d\n",mallocs);
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]);
307 fprintf(stderr,"%s\n",head+1);
314 debug_malloc(const char *where, int line, const char *func, int size)
316 struct malloc_head *head;
317 struct malloc_tail *tail;
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);
326 head=malloc(size+sizeof(*head)+sizeof(*tail));
327 head->magic=0xdeadbeef;
330 head->next=malloc_heads;
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
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);
347 tail=(struct malloc_tail *)((unsigned char *)head+size);
348 tail->magic=0xdeadbef0;
354 debug_malloc0(const char *where, int line, const char *func, int size)
356 void *ret=debug_malloc(where, line, func, size);
358 memset(ret, 0, size);
363 debug_realloc(const char *where, int line, const char *func, void *ptr, int size)
365 void *ret=debug_malloc(where, line, func, size);
367 memcpy(ret, ptr, size);
368 debug_free(where, line, func, ptr);
373 debug_strdup(const char *where, int line, const char *func, const char *ptr)
381 ret=debug_malloc(where, line, func, size);
382 memcpy(ret, ptr, size);
387 debug_guard(const char *where, int line, const char *func, char *str)
389 char *ret=debug_strdup(where, line, func, str);
395 debug_free(const char *where, int line, const char *func, void *ptr)
397 struct malloc_head *head;
398 struct malloc_tail *tail;
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);
411 head->prev->next=head->next;
413 malloc_heads=head->next;
415 head->next->prev=head->prev;
421 debug_free_func(void *ptr)
423 debug_free("unknown",0,"unknown",ptr);
426 void debug_finished(void) {
427 debug_dump_mallocs();
429 g_hash_table_destroy(debug_hash);