fix a warning
[platform/upstream/gstreamer.git] / gst / gstinfo.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstinfo.c: INFO, ERROR, and DEBUG systems
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <dlfcn.h>
24 #include "gst_private.h"
25 #include "gstelement.h"
26 #include "gstpad.h"
27 #include "gstscheduler.h"
28
29 #if defined __sgi__
30 #include <rld_interface.h>
31 typedef struct DL_INFO {
32   const char * dli_fname;
33   void       * dli_fbase;
34   const char * dli_sname;
35   void       * dli_saddr;
36   int          dli_version;
37   int          dli_reserved1;
38   long         dli_reserved[4];
39 } Dl_info;
40 #define _RLD_DLADDR             14
41 int dladdr(void *address, Dl_info *dl);
42
43 int dladdr(void *address, Dl_info *dl)
44 {
45   void *v;
46   v = _rld_new_interface(_RLD_DLADDR,address,dl);
47   return (int)v;
48 }
49 #endif
50
51 extern gchar *_gst_progname;
52
53
54 /***** Categories and colorization *****/
55 /* be careful with these, make them match the enum */
56 static gchar *_gst_info_category_strings[] = {
57   /* [GST_CAT_GST_INIT]         = */ "GST_INIT",
58   /* [GST_CAT_COTHREADS]        = */ "COTHREADS",
59   /* [GST_CAT_COTHREAD_SWITCH]  = */ "COTHREAD_SWITCH",
60   /* [GST_CAT_AUTOPLUG]         = */ "AUTOPLUG",
61   /* [GST_CAT_AUTOPLUG_ATTEMPT] = */ "AUTOPLUG_ATTEMPT",
62   /* [GST_CAT_PARENTAGE]        = */ "PARENTAGE",
63   /* [GST_CAT_STATES]           = */ "STATES",
64   /* [GST_CAT_PLANNING]         = */ "PLANNING",
65   /* [GST_CAT_SCHEDULING]       = */ "SCHEDULING",
66   /* [GST_CAT_DATAFLOW]         = */ "DATAFLOW",
67   /* [GST_CAT_BUFFER]           = */ "BUFFER",
68   /* [GST_CAT_CAPS]             = */ "CAPS",
69   /* [GST_CAT_CLOCK]            = */ "CLOCK",
70   /* [GST_CAT_ELEMENT_PADS]     = */ "ELEMENT_PADS",
71   /* [GST_CAT_ELEMENT_FACTORY]  = */ "ELEMENTFACTORY",
72   /* [GST_CAT_PADS]             = */ "PADS",
73   /* [GST_CAT_PIPELINE]         = */ "PIPELINE",
74   /* [GST_CAT_PLUGIN_LOADING]   = */ "PLUGIN_LOADING",
75   /* [GST_CAT_PLUGIN_ERRORS]    = */ "PLUGIN_ERRORS",
76   /* [GST_CAT_PLUGIN_INFO]      = */ "PLUGIN_INFO",
77   /* [GST_CAT_PROPERTIES]       = */ "PROPERTIES",
78   /* [GST_CAT_THREAD]           = */ "THREAD",
79   /* [GST_CAT_TYPES]            = */ "TYPES",
80   /* [GST_CAT_XML]              = */ "XML",
81   /* [GST_CAT_NEGOTIATION]      = */ "NEGOTIATION",
82   /* [GST_CAT_REFCOUNTING]      = */ "REFCOUNTING",
83   /* [GST_CAT_EVENT]            = */ "EVENT",
84   /* [GST_CAT_PARAMS]           = */ "PARAMS",
85   "",
86   "",
87   /* [GST_CAT_CALL_TRACE]       = */ "CALL_TRACE",
88   /* [31]                       = */ 
89 };
90
91 /**
92  * gst_get_category_name:
93  * @category: the category to return the name of
94  *
95  * Return a string containing the name of the category
96  *
97  * Returns: string containing the name of the category
98  */
99 const gchar *
100 gst_get_category_name (gint category) {
101   if ((category >= 0) && (category < GST_CAT_MAX_CATEGORY))
102     return _gst_info_category_strings[category];
103   else
104     return NULL;
105 }
106
107
108 /*
109  * Attribute codes:
110  * 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
111  * Text color codes:
112  * 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
113  * Background color codes:
114  * 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
115  */
116 /* be careful with these, make them match the enum */
117 const gchar *_gst_category_colors[32] = {
118   /* [GST_CAT_GST_INIT]         = */ "07;37",
119   /* [GST_CAT_COTHREADS]        = */ "00;32",
120   /* [GST_CAT_COTHREAD_SWITCH]  = */ "00;37;42",
121   /* [GST_CAT_AUTOPLUG]         = */ "00;34",
122   /* [GST_CAT_AUTOPLUG_ATTEMPT] = */ "00;36;44",
123   /* [GST_CAT_PARENTAGE]        = */ "01;37;41",        /* !! */
124   /* [GST_CAT_STATES]           = */ "00;31",
125   /* [GST_CAT_PLANNING]         = */ "07;35",
126   /* [GST_CAT_SCHEDULING]       = */ "00;35",
127   /* [GST_CAT_DATAFLOW]         = */ "00;32",
128   /* [GST_CAT_BUFFER]           = */ "00;32",
129   /* [GST_CAT_CAPS]             = */ "04;34",
130   /* [GST_CAT_CLOCK]            = */ "00;33",           /* !! */
131   /* [GST_CAT_ELEMENT_PADS]     = */ "01;37;41",        /* !! */
132   /* [GST_CAT_ELEMENT_FACTORY]  = */ "01;37;41",        /* !! */
133   /* [GST_CAT_PADS]             = */ "01;37;41",        /* !! */
134   /* [GST_CAT_PIPELINE]         = */ "01;37;41",        /* !! */
135   /* [GST_CAT_PLUGIN_LOADING]   = */ "00;36",
136   /* [GST_CAT_PLUGIN_ERRORS]    = */ "05;31",
137   /* [GST_CAT_PLUGIN_INFO]      = */ "00;36",
138   /* [GST_CAT_PROPERTIES]       = */ "00;37;44",        /* !! */
139   /* [GST_CAT_THREAD]           = */ "00;31",
140   /* [GST_CAT_TYPES]            = */ "01;37;41",        /* !! */
141   /* [GST_CAT_XML]              = */ "01;37;41",        /* !! */
142   /* [GST_CAT_NEGOTIATION]      = */ "07;34",
143   /* [GST_CAT_REFCOUNTING]      = */ "00;34:42",
144   /* [GST_CAT_EVENT]            = */ "01;37;41",        /* !! */
145   /* [GST_CAT_PARAMS]           = */ "00;30;43",        /* !! */
146                                      "",
147                                      "",
148   /* [GST_CAT_CALL_TRACE]       = */ "",
149   /* [31]                       = */ "05;31",
150 };
151
152 /* colorization hash - DEPRACATED in favor of above */
153 inline gint _gst_debug_stringhash_color(gchar *file) {
154   int filecolor = 0;
155   while (file[0]) filecolor += *(char *)(file++);
156   filecolor = (filecolor % 6) + 31;
157   return filecolor;
158 }
159
160
161 /***** DEBUG system *****/
162 GstDebugHandler _gst_debug_handler = gst_default_debug_handler;
163 guint32 _gst_debug_categories = 0x00000000;
164
165 /**
166  * gst_default_debug_handler:
167  * @category: category of the DEBUG message
168  * @incore: if the debug handler is for core code.
169  * @file: the file the DEBUG occurs in
170  * @function: the function the DEBUG occurs in
171  * @line: the line number in the file
172  * @debug_string: the current debug_string in the function, if any
173  * @element: pointer to the #GstElement in question
174  * @string: the actual DEBUG string
175  *
176  * Prints out the DEBUG mesage in a variant of the following form:
177  *
178  *   DEBUG(pid:cid):gst_function:542(args): [elementname] something neat happened
179  */
180 void
181 gst_default_debug_handler (gint category, gboolean incore,
182                            const gchar *file, const gchar *function,
183                            gint line, const gchar *debug_string,
184                            void *element, gchar *string)
185   G_GNUC_NO_INSTRUMENT;
186
187 void
188 gst_default_debug_handler (gint category, gboolean incore,
189                            const gchar *file, const gchar *function,
190                            gint line, const gchar *debug_string,
191                            void *element, gchar *string)
192 {
193   gchar *empty = "";
194   gchar *elementname = empty,*location = empty;
195   int pid = getpid();
196   int cothread_id = 0; /*FIXME*/
197 #ifdef GST_DEBUG_COLOR
198   int pid_color = pid%6 + 31;
199   int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
200 #endif
201
202   if (debug_string == NULL) debug_string = "";
203 /*  if (category != GST_CAT_GST_INIT) */
204     location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
205   if (element && GST_IS_ELEMENT (element))
206 #ifdef GST_DEBUG_COLOR
207     elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
208 #else
209     elementname = g_strdup_printf (" [%s]", GST_OBJECT_NAME (element));
210 #endif
211
212 #ifdef GST_DEBUG_COLOR
213   fprintf(stderr,"DEBUG(\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
214           "%s;%sm%s%s\033[00m %s\n",
215           pid_color,pid,cothread_color,cothread_id,incore?"00":"01",
216           _gst_category_colors[category],location,elementname,string);
217 #else
218   fprintf(stderr,"DEBUG(%5d:%2d)%s%s %s\n",
219           pid,cothread_id,location,elementname,string);
220 #endif /* GST_DEBUG_COLOR */
221
222   if (location != empty) g_free(location);
223   if (elementname != empty) g_free(elementname);
224
225   g_free(string);
226 }
227
228
229 /**
230  * gst_debug_set_categories:
231  * @categories: bitmask of DEBUG categories to enable
232  *
233  * Enable the output of DEBUG categories based on the given bitmask.
234  * The bit for any given category is (1 << GST_CAT_...).
235  */
236 void
237 gst_debug_set_categories (guint32 categories) {
238   _gst_debug_categories = categories;
239 }
240
241 /**
242  * gst_debug_get_categories:
243  *
244  * Return the current bitmask of enabled DEBUG categories
245  *
246  * Returns: the current bitmask of enabled DEBUG categories
247  * The bit for any given category is (1 << GST_CAT_...).
248  */
249 guint32
250 gst_debug_get_categories () {
251   return _gst_debug_categories;
252 }
253
254 /**
255  * gst_debug_enable_category:
256  * @category: the category to enable
257  *
258  * Enables the given GST_CAT_... DEBUG category.
259  */
260 void
261 gst_debug_enable_category (gint category) {
262   _gst_debug_categories |= (1 << category);
263 }
264
265 /**
266  * gst_debug_disable_category:
267  * @category: the category to disable
268  *
269  * Disables the given GST_CAT_... DEBUG category.
270  */
271 void
272 gst_debug_disable_category (gint category) {
273   _gst_debug_categories &= ~ (1 << category);
274 }
275
276
277
278
279 /***** INFO system *****/
280 GstInfoHandler _gst_info_handler = gst_default_info_handler;
281 guint32 _gst_info_categories = 0x00000001;
282
283
284 /**
285  * gst_default_info_handler:
286  * @category: category of the INFO message
287  * @incore: if the info handler is for core code.
288  * @file: the file the INFO occurs in
289  * @function: the function the INFO occurs in
290  * @line: the line number in the file
291  * @debug_string: the current debug_string in the function, if any
292  * @element: pointer to the #GstElement in question
293  * @string: the actual INFO string
294  *
295  * Prints out the INFO mesage in a variant of the following form:
296  *
297  *   INFO:gst_function:542(args): [elementname] something neat happened
298  */
299 void
300 gst_default_info_handler (gint category, gboolean incore,
301                           const gchar *file, const gchar *function,
302                           gint line, const gchar *debug_string,
303                           void *element, gchar *string)
304 {
305   gchar *empty = "";
306   gchar *elementname = empty,*location = empty;
307   int pid = getpid();
308   int cothread_id = 0; /*FIXME*/
309 #ifdef GST_DEBUG_COLOR
310   int pid_color = pid%6 + 31;
311   int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
312 #endif
313
314   if (debug_string == NULL) debug_string = "";
315   if (category != GST_CAT_GST_INIT)
316     location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
317   if (element && GST_IS_ELEMENT (element))
318     elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
319
320 /*
321 #ifdef GST_DEBUG_ENABLED
322 */
323   #ifdef GST_DEBUG_COLOR
324     fprintf(stderr,"\033[01mINFO\033[00m (\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
325             GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
326             pid_color,pid,cothread_color,cothread_id,
327             _gst_category_colors[category],location,elementname,string);
328   #else
329     fprintf(stderr,"INFO (%5d:%2d)%s%s %s\n",
330             pid,cothread_id,location,elementname,string);
331 #endif /* GST_DEBUG_COLOR */
332 /*
333 #else
334   #ifdef GST_DEBUG_COLOR
335     fprintf(stderr,"\033[01mINFO\033[00m:\033[" GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
336             location,elementname,_gst_category_colors[category],string);
337   #else
338     fprintf(stderr,"INFO:%s%s %s\n",
339             location,elementname,string);
340   #endif * GST_DEBUG_COLOR *
341
342 #endif
343 */
344
345   if (location != empty) g_free(location);
346   if (elementname != empty) g_free(elementname);
347
348   g_free(string);
349 }
350
351 /**
352  * gst_info_set_categories:
353  * @categories: bitmask of INFO categories to enable
354  *
355  * Enable the output of INFO categories based on the given bitmask.
356  * The bit for any given category is (1 << GST_CAT_...).
357  */
358 void
359 gst_info_set_categories (guint32 categories) {
360   _gst_info_categories = categories;
361 }
362
363 /**
364  * gst_info_get_categories:
365  *
366  * Return the current bitmask of enabled INFO categories
367  * The bit for any given category is (1 << GST_CAT_...).
368  *
369  * Returns: the current bitmask of enabled INFO categories
370  * The bit for any given category is (1 << GST_CAT_...).
371  */
372 guint32
373 gst_info_get_categories () {
374   return _gst_info_categories;
375 }
376
377 /**
378  * gst_info_enable_category:
379  * @category: the category to enable
380  *
381  * Enables the given GST_CAT_... INFO category.
382  */
383 void
384 gst_info_enable_category (gint category) {
385   _gst_info_categories |= (1 << category);
386 }
387
388 /**
389  * gst_info_disable_category:
390  * @category: the category to disable
391  *
392  * Disables the given GST_CAT_... INFO category.
393  */
394 void
395 gst_info_disable_category (gint category) {
396   _gst_info_categories &= ~ (1 << category);
397 }
398
399
400
401 /***** ERROR system *****/
402 GstErrorHandler _gst_error_handler = gst_default_error_handler;
403
404 /**
405  * gst_default_error_handler:
406  * @file: the file the ERROR occurs in
407  * @function: the function the INFO occurs in
408  * @line: the line number in the file
409  * @debug_string: the current debug_string in the function, if any
410  * @element: pointer to the #GstElement in question
411  * @object: pointer to a related object
412  * @string: the actual ERROR string
413  *
414  * Prints out the given ERROR string in a variant of the following format:
415  *
416  * ***** GStreamer ERROR ***** in file gstsomething.c at gst_function:399(arg)
417  * Element: /pipeline/thread/element.src
418  * Error: peer is null!
419  * ***** attempting to stack trace.... *****
420  *
421  * At the end, it attempts to print the stack trace via GDB.
422  */
423 void
424 gst_default_error_handler (gchar *file, gchar *function,
425                            gint line, gchar *debug_string,
426                            void *element, void *object, gchar *string)
427 {
428   int chars = 0;
429   gchar *path;
430   int i;
431
432   /* if there are NULL pointers, point them to null strings to clean up output */
433   if (!debug_string) debug_string = "";
434   if (!string) string = "";
435
436   /* print out a preamble */
437   fprintf(stderr,"***** GStreamer ERROR ***** in file %s at %s:%d%s\n",
438           file,function,line,debug_string);
439
440   /* if there's an element, print out the pertinent information */
441   if (element) {
442     if (GST_IS_OBJECT(element)) {
443       path = gst_object_get_path_string(element);
444       fprintf(stderr,"Element: %s",path);
445       chars = 9 + strlen(path);
446       g_free(path);
447     } else {
448       fprintf(stderr,"Element ptr: %p",element);
449       chars = 15 + sizeof(void*)*2;
450     }
451   }
452
453   /* if there's an object, print it out as well */
454   if (object) {
455     /* attempt to pad the line, or create a new one */
456     if (chars < 40)
457       for (i=0;i<(40-chars)/8+1;i++) fprintf(stderr,"\t");
458     else
459       fprintf(stderr,"\n");
460
461     if (GST_IS_OBJECT(object)) {
462       path = gst_object_get_path_string(object);
463       fprintf(stderr,"Object: %s",path);
464       g_free(path);
465     } else {
466       fprintf(stderr,"Object ptr: %p",object);
467     }
468   }
469
470   fprintf(stderr,"\n");
471   fprintf(stderr,"Error: %s\n",string);
472
473   g_free(string);
474
475   fprintf(stderr,"***** attempting to stack trace.... *****\n");
476
477   g_on_error_stack_trace (_gst_progname);
478
479   exit(1);
480 }
481
482
483
484 /***** DEBUG system *****/
485 #ifdef GST_DEBUG_ENABLED
486 GHashTable *__gst_function_pointers = NULL;
487 /* FIXME make this thread specific */
488 /* static GSList *stack_trace = NULL; */
489
490 gchar *_gst_debug_nameof_funcptr (void *ptr) G_GNUC_NO_INSTRUMENT;
491
492 gchar *
493 _gst_debug_nameof_funcptr (void *ptr)
494 {
495   gchar *ptrname;
496   Dl_info dlinfo;
497   if (__gst_function_pointers && (ptrname = g_hash_table_lookup(__gst_function_pointers,ptr))) {
498     return g_strdup(ptrname);
499   } else if (dladdr(ptr,&dlinfo) && dlinfo.dli_sname) {
500     return g_strdup(dlinfo.dli_sname);
501   } else {
502     return g_strdup_printf("%p",ptr);
503   }
504   return NULL;
505 }
506 #endif
507
508
509 #ifdef GST_ENABLE_FUNC_INSTRUMENTATION
510 void __cyg_profile_func_enter(void *this_fn,void *call_site) G_GNUC_NO_INSTRUMENT;
511 void __cyg_profile_func_enter(void *this_fn,void *call_site) 
512 {
513   gchar *name = _gst_debug_nameof_funcptr (this_fn);
514   gchar *site = _gst_debug_nameof_funcptr (call_site);
515         
516   GST_DEBUG(GST_CAT_CALL_TRACE, "entering function %s from %s", name, site);
517   stack_trace = g_slist_prepend (stack_trace, g_strdup_printf ("%8p in %s from %p (%s)", this_fn, name, call_site, site));
518
519   g_free (name);
520   g_free (site);
521 }
522
523 void __cyg_profile_func_exit(void *this_fn,void *call_site) G_GNUC_NO_INSTRUMENT;
524 void __cyg_profile_func_exit(void *this_fn,void *call_site) 
525 {
526   gchar *name = _gst_debug_nameof_funcptr (this_fn);
527
528   GST_DEBUG(GST_CAT_CALL_TRACE, "leaving function %s", name);
529   g_free (stack_trace->data);
530   stack_trace = g_slist_delete_link (stack_trace, stack_trace);
531
532   g_free (name);
533 }
534
535 void 
536 gst_debug_print_stack_trace (void)
537 {
538   GSList *walk = stack_trace;
539   gint count = 0;
540
541   if (walk)
542     walk = g_slist_next (walk);
543
544   while (walk) {
545     gchar *name = (gchar *) walk->data;
546
547     g_print ("#%-2d %s\n", count++, name);
548
549     walk = g_slist_next (walk);
550   }
551 }
552 #else
553 void 
554 gst_debug_print_stack_trace (void)
555 {
556   /* nothing because it's compiled out */
557 }
558
559 #endif /* GST_ENABLE_FUNC_INTSTRUMENTATION */