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