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);
96 debug_update_level(gpointer key, gpointer value, gpointer user_data)
98 if (debug_level < GPOINTER_TO_INT(value))
99 debug_level = GPOINTER_TO_INT(value);
103 debug_level_set(const char *name, int level)
105 if (!strcmp(name, "segv")) {
108 signal(SIGSEGV, sigsegv);
110 signal(SIGSEGV, NULL);
111 } else if (!strcmp(name, "timestamps")) {
112 timestamp_prefix=level;
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);
121 debug_new(struct attr *parent, struct attr **attrs)
123 struct attr *name,*level;
124 name=attr_search(attrs, NULL, attr_name);
125 level=attr_search(attrs, NULL, attr_level);
127 if (!name && !level) {
128 struct attr *socket_attr=attr_search(attrs, NULL, attr_socket);
132 s=g_strdup(socket_attr->u.str);
139 debug_sin.sin_family=AF_INET;
140 if (!inet_aton(s, &debug_sin.sin_addr)) {
144 debug_sin.sin_port=ntohs(atoi(p));
145 if (debug_socket == -1)
146 debug_socket=socket(PF_INET, SOCK_DGRAM, 0);
148 return (struct debug *)&dummy;
153 debug_level_set(name->u.str, level->u.num);
154 return (struct debug *)&dummy;
159 debug_level_get(const char *name)
163 return GPOINTER_TO_INT(g_hash_table_lookup(debug_hash, name));
166 static void debug_timestamp(char *buffer)
168 #if defined HAVE_API_WIN32_CE || defined _MSC_VER
169 LARGE_INTEGER counter, frequency;
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);
180 if (gettimeofday(&tv, NULL) == -1)
182 /* Timestamps are UTC */
184 "%02d:%02d:%02d.%03d|",
185 (int)(tv.tv_sec/3600)%24,
186 (int)(tv.tv_sec/60)%60,
188 (int)tv.tv_usec/1000);
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)
195 #if defined HAVE_API_WIN32_CE || defined _MSC_VER
198 char buffer[mlen+flen+3];
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)
210 if (timestamp_prefix)
211 debug_timestamp(xbuffer);
212 strcpy(xbuffer+strlen(xbuffer),buffer);
213 strcpy(xbuffer+strlen(xbuffer),":");
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);
220 #ifdef HAVE_API_ANDROID
221 __android_log_print(ANDROID_LOG_ERROR,"navit", "%s", xbuffer);
224 if (debug_socket != -1) {
225 sendto(debug_socket, xbuffer, strlen(xbuffer), 0, (struct sockaddr *)&debug_sin, sizeof(debug_sin));
231 fprintf(fp,"%s",xbuffer);
239 debug_printf(int level, const char *module, const int mlen,const char *function, const int flen, int prefix, const char *fmt, ...)
243 debug_vprintf(level, module, mlen, function, flen, prefix, fmt, ap);
248 debug_assert_fail(const char *module, const int mlen,const char *function, const int flen, const char *file, int line, const char *expr)
250 debug_printf(0,module,mlen,function,flen,1,"%s:%d assertion failed:%s\n", file, line, expr);
259 if (debug_fp == stderr || debug_fp == stdout)
265 void debug_set_logfile(const char *path)
268 fp = fopen(path, "a");
272 fprintf(debug_fp, "Navit log started\n");
281 void *return_address[8];
282 struct malloc_head *prev;
283 struct malloc_head *next;
290 int mallocs,debug_malloc_size,debug_malloc_size_m;
293 debug_dump_mallocs(void)
295 struct malloc_head *head=malloc_heads;
297 dbg(0,"mallocs %d\n",mallocs);
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]);
303 fprintf(stderr,"%s\n",head+1);
310 debug_malloc(const char *where, int line, const char *func, int size)
312 struct malloc_head *head;
313 struct malloc_tail *tail;
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);
322 head=malloc(size+sizeof(*head)+sizeof(*tail));
323 head->magic=0xdeadbeef;
326 head->next=malloc_heads;
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
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);
343 tail=(struct malloc_tail *)((unsigned char *)head+size);
344 tail->magic=0xdeadbef0;
350 debug_malloc0(const char *where, int line, const char *func, int size)
352 void *ret=debug_malloc(where, line, func, size);
354 memset(ret, 0, size);
359 debug_realloc(const char *where, int line, const char *func, void *ptr, int size)
361 void *ret=debug_malloc(where, line, func, size);
363 memcpy(ret, ptr, size);
364 debug_free(where, line, func, ptr);
369 debug_strdup(const char *where, int line, const char *func, const char *ptr)
377 ret=debug_malloc(where, line, func, size);
378 memcpy(ret, ptr, size);
383 debug_guard(const char *where, int line, const char *func, char *str)
385 char *ret=debug_strdup(where, line, func, str);
391 debug_free(const char *where, int line, const char *func, void *ptr)
393 struct malloc_head *head;
394 struct malloc_tail *tail;
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);
407 head->prev->next=head->next;
409 malloc_heads=head->next;
411 head->next->prev=head->prev;
417 debug_free_func(void *ptr)
419 debug_free("unknown",0,"unknown",ptr);
422 void debug_finished(void) {
423 debug_dump_mallocs();
425 g_hash_table_destroy(debug_hash);