Tizen 2.1 base
[sdk/emulator/qemu.git] / tizen / src / debug_ch_vtm.c
1 /*
2  * Management of the debugging channels
3  *
4  * Copyright 2000 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 /**
22  * @file        debug_ch.c
23  * @brief       Management of the debugging channels
24  *
25  * @author
26  * @date
27  * @attention
28  */
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <string.h>
34 #include <assert.h>
35 #include <unistd.h>
36 #include "debug_ch.h"
37 #include "fileio.h"
38
39 extern STARTUP_OPTION startup_option;
40 static char logfile[256] = { 0, };
41 static char debugchfile[256] = {0, };
42 static inline int interlocked_xchg_add( int *dest, int incr )
43 {
44         int ret;
45         __asm__ __volatile__( "lock; xaddl %0,(%1)"
46                         : "=r" (ret) : "r" (dest), "0" (incr) : "memory" );
47         return ret;
48 }
49
50 static const char * const debug_classes[] = {"fixme", "err", "warn", "trace", "info"};
51
52 #define MAX_DEBUG_OPTIONS 256
53
54 //static unsigned char default_flags = (1 << __DBCL_ERR) | (1 << __DBCL_FIXME) | (1 << __DBCL_INFO);
55 static unsigned char default_flags = (1 << __DBCL_ERR)  | (1 << __DBCL_INFO);
56 static int nb_debug_options = -1;
57 static struct _debug_channel debug_options[MAX_DEBUG_OPTIONS];
58
59 static void debug_init(void);
60
61 static int cmp_name( const void *p1, const void *p2 )
62 {
63         const char *name = p1;
64         const struct _debug_channel *chan = p2;
65         return strcmp( name, chan->name );
66 }
67
68 /* get the flags to use for a given channel, possibly setting them too in case of lazy init */
69 unsigned char _dbg_get_channel_flags( struct _debug_channel *channel )
70 {
71         if (nb_debug_options == -1)
72                 debug_init();
73
74         if(nb_debug_options){
75                 struct _debug_channel *opt;
76
77                 /* first check for multi channel */
78                 opt = bsearch( channel->multiname,
79                                 debug_options,
80                                 nb_debug_options,
81                                 sizeof(debug_options[0]), cmp_name );
82                 if (opt)
83                         return opt->flags;
84
85                 opt = bsearch( channel->name,
86                                 debug_options,
87                                 nb_debug_options,
88                                 sizeof(debug_options[0]), cmp_name );
89                 if (opt){
90                         return opt->flags;
91                 }
92         }
93
94         /* no option for this channel */
95         if (channel->flags & (1 << __DBCL_INIT))
96                 channel->flags = default_flags;
97
98         return default_flags;
99 }
100
101 /* set the flags to use for a given channel; return 0 if the channel is not available to set */
102 int _dbg_set_channel_flags( struct _debug_channel *channel,
103                 unsigned char set, unsigned char clear )
104 {
105         if (nb_debug_options == -1)
106                 debug_init();
107
108         if (nb_debug_options){
109                 struct _debug_channel *opt;
110
111                 /* first set for multi channel */
112                 opt = bsearch( channel->multiname,
113                                 debug_options,
114                                 nb_debug_options,
115                                 sizeof(debug_options[0]), cmp_name );
116                 if (opt){
117                         opt->flags = (opt->flags & ~clear) | set;
118                         return 1;
119                 }
120
121                 opt = bsearch( channel->name,
122                                 debug_options,
123                                 nb_debug_options,
124                                 sizeof(debug_options[0]), cmp_name );
125                 if (opt){
126                         opt->flags = (opt->flags & ~clear) | set;
127                         return 1;
128                 }
129         }
130         return 0;
131 }
132
133 /* add a new debug option at the end of the option list */
134 static void add_option( const char *name, unsigned char set, unsigned char clear )
135 {
136         int min = 0, max = nb_debug_options - 1, pos, res;
137
138         if (!name[0])  /* "all" option */
139         {
140                 default_flags = (default_flags & ~clear) | set;
141                 return;
142         }
143
144         if (strlen(name) >= sizeof(debug_options[0].name))
145                 return;
146
147         while (min <= max)
148         {
149                 pos = (min + max) / 2;
150                 res = strcmp( name, debug_options[pos].name );
151                 if (!res)
152                 {
153                         debug_options[pos].flags = (debug_options[pos].flags & ~clear) | set;
154                         return;
155                 }
156                 if (res < 0)
157                         max = pos - 1;
158                 else
159                         min = pos + 1;
160         }
161         if (nb_debug_options >= MAX_DEBUG_OPTIONS)
162                 return;
163
164         pos = min;
165         if (pos < nb_debug_options) {
166                 memmove( &debug_options[pos + 1],
167                                 &debug_options[pos],
168                                 (nb_debug_options - pos) * sizeof(debug_options[0]) );
169         }
170
171         strcpy( debug_options[pos].name, name );
172         debug_options[pos].flags = (default_flags & ~clear) | set;
173         nb_debug_options++;
174 }
175
176 /* parse a set of debugging option specifications and add them to the option list */
177 static void parse_options( const char *str )
178 {
179         char *opt, *next, *options;
180         unsigned int i;
181
182         if (!(options = strdup(str)))
183                 return;
184         for (opt = options; opt; opt = next)
185         {
186                 const char *p;
187                 unsigned char set = 0, clear = 0;
188
189                 if ((next = strchr( opt, ',' )))
190                         *next++ = 0;
191
192                 p = opt + strcspn( opt, "+-" );
193                 if (!p[0])
194                         p = opt;  /* assume it's a debug channel name */
195
196                 if (p > opt)
197                 {
198                         for (i = 0; i < sizeof(debug_classes)/sizeof(debug_classes[0]); i++)
199                         {
200                                 int len = strlen(debug_classes[i]);
201                                 if (len != (p - opt))
202                                         continue;
203                                 if (!memcmp( opt, debug_classes[i], len ))  /* found it */
204                                 {
205                                         if (*p == '+')
206                                                 set |= 1 << i;
207                                         else
208                                                 clear |= 1 << i;
209                                         break;
210                                 }
211                         }
212                         if (i == sizeof(debug_classes)/sizeof(debug_classes[0])) /* bad class name, skip it */
213                                 continue;
214                 }
215                 else
216                 {
217                         if (*p == '-')
218                                 clear = ~0;
219                         else
220                                 set = ~0;
221                 }
222                 if (*p == '+' || *p == '-')
223                         p++;
224                 if (!p[0])
225                         continue;
226
227                 if (!strcmp( p, "all" ))
228                         default_flags = (default_flags & ~clear) | set;
229                 else
230                         add_option( p, set, clear );
231         }
232         free( options );
233 }
234
235 /* print the usage message */
236 static void debug_usage(void)
237 {
238         static const char usage[] =
239                 "Syntax of the DEBUGCH variable:\n"
240                 "  DEBUGCH=[class]+xxx,[class]-yyy,...\n\n"
241                 "Example: DEBUGCH=+all,warn-heap\n"
242                 "    turns on all messages except warning heap messages\n"
243                 "Available message classes: err, warn, fixme, trace\n";
244         const int ret = write( 2, usage, sizeof(usage) - 1 );
245         assert(ret >= 0);
246         exit(1);
247 }
248
249 /* initialize all options at startup */
250 static void debug_init(void)
251 {
252         char *debug = NULL;
253         FILE *fp = NULL;
254         char *tmp = NULL;
255         char *tizen_vms_path = NULL;
256
257         if (nb_debug_options != -1)
258                 return;  /* already initialized */
259
260         nb_debug_options = 0;
261         strcpy(debugchfile, get_etc_path());
262         strcat(debugchfile, "/DEBUGCH");
263
264         fp= fopen(debugchfile, "r");
265         if( fp == NULL){
266                 debug = getenv("DEBUGCH");
267         }else{
268                 if ((tmp= (char *)malloc(1024 + 1)) == NULL){
269                         fclose(fp);
270                         return;
271                 }
272
273                 fseek(fp, 0, SEEK_SET);
274                 const char* str = fgets(tmp, 1024, fp);
275                 if (str) {
276                         tmp[strlen(tmp)-1] = 0;
277                         debug = tmp;
278                 }
279
280                 fclose(fp);
281         }
282
283         if( debug != NULL ){
284                 if (!strcmp( debug, "help" ))
285                         debug_usage();
286                 parse_options( debug );
287         }
288
289         if( tmp != NULL ){
290                 free(tmp);
291         }
292
293         //to make logfile, create tizen_vms dir 
294         tizen_vms_path = (char*)get_tizen_vms_path();
295         if(access(tizen_vms_path, R_OK) != 0){
296                 g_mkdir_with_parents(tizen_vms_path, 0755);
297         }
298         strcpy(logfile, tizen_vms_path);
299         strcat(logfile, EMULMGR_LOGFILE);
300         
301         free(tizen_vms_path);
302
303         if(access(logfile, F_OK | R_OK) == 0)
304                 remove(logfile);
305 }
306
307 /* allocate some tmp string space */
308 /* FIXME: this is not 100% thread-safe */
309 char *get_dbg_temp_buffer( size_t size )
310 {
311         static char *list[32];
312         static int pos;
313         char *ret;
314         int idx;
315
316         idx = interlocked_xchg_add( &pos, 1 ) % (sizeof(list)/sizeof(list[0]));
317
318         if ((ret = realloc( list[idx], size )))
319                 list[idx] = ret;
320
321         return ret;
322 }
323
324 /* release unused part of the buffer */
325 void release_dbg_temp_buffer( char *buffer, size_t size )
326 {
327         /* don't bother doing anything */
328         (void)( buffer );
329         (void)( size );
330 }
331
332 static int dbg_vprintf( const char *format, va_list args )
333 {
334         char tmp[MSGSIZE_MAX] = { 0, };
335         char txt[MSGSIZE_MAX] = { 0, };
336
337         FILE *fp;
338         // lock
339
340         int ret = vsnprintf( tmp, MSGSIZE_MAX, format, args );
341
342         tmp[MSGSIZE_MAX - 2] = '\n';
343         tmp[MSGSIZE_MAX - 1] = 0;
344
345         sprintf(txt, "%s", tmp);
346
347         // unlock
348         if ((fp = fopen(logfile, "a+")) == NULL) {
349                 fprintf(stdout, "Emulator manager can't open.\n"
350                                 "Please check if "
351                                 "this binary file is running on the right path.\n");
352                 exit(1);
353         }
354
355         fputs(txt, fp);
356         fclose(fp);
357
358         return ret;
359 }
360
361 int dbg_printf( const char *format, ... )
362 {
363         int ret;
364         va_list valist;
365
366         va_start(valist, format);
367         ret = dbg_vprintf( format, valist );
368         va_end(valist);
369
370         return ret;
371 }
372
373 int dbg_printf_nonewline( const char *format, ... )
374 {
375         int ret;
376         va_list valist;
377
378         va_start(valist, format);
379         ret = dbg_vprintf( format, valist );
380         va_end(valist);
381
382         return ret;
383 }
384
385 /* printf with temp buffer allocation */
386 const char *dbg_sprintf( const char *format, ... )
387 {
388         static const int max_size = 200;
389         char *ret;
390         int len;
391         va_list valist;
392
393         va_start(valist, format);
394         ret = get_dbg_temp_buffer( max_size );
395         len = vsnprintf( ret, max_size, format, valist );
396         if (len == -1 || len >= max_size)
397                 ret[max_size-1] = 0;
398         else
399                 release_dbg_temp_buffer( ret, len + 1 );
400         va_end(valist);
401         return ret;
402 }
403
404 /* default implementation of dbg_vlog */
405 static int dbg_vlog( enum _debug_class cls, struct _debug_channel *channel,
406                 const char *format, va_list args )
407 {
408         int ret = 0;
409
410         if (cls < sizeof(debug_classes)/sizeof(debug_classes[0])) {
411                 (void)(channel);
412                 /* to print debug class, channel */
413                 ret += dbg_printf_nonewline("[%s:%s"
414                                 , debug_classes[cls] , channel->name);
415
416                 if (*channel->multiname)
417                         ret += dbg_printf_nonewline(":%s] ", channel->multiname);
418                 else
419                         ret += dbg_printf_nonewline("] ");
420         }
421         if (format) {
422                 ret += dbg_vprintf( format, args );
423         }
424         return ret;
425 }
426
427 int dbg_log( enum _debug_class cls, struct _debug_channel *channel,
428                 const char *format, ... )
429 {
430         int ret;
431         va_list valist;
432
433         if (!(_dbg_get_channel_flags( channel ) & (1 << cls)))
434                 return -1;
435
436         va_start(valist, format);
437         ret = dbg_vlog( cls, channel, format, valist );
438         va_end(valist);
439
440         fflush(stderr);
441
442         return ret;
443 }
444
445 void assert_fail(char *exp, const char *file, int line)
446 {
447         fprintf(stderr, "[%s][%d] Assert(%s) failed \n"
448                         , file, line, exp);
449         fprintf(stdout, "[%s][%d] Assert(%s) failed \n"
450                         , file, line, exp);
451         exit(0);
452 }
453
454 /* end of debug_ch.c */