2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
5 * gstinfo.c: INFO, ERROR, and DEBUG systems
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.
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.
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.
24 #include "gst_private.h"
25 #include "gstelement.h"
27 #include "gstscheduler.h"
30 #include <rld_interface.h>
31 typedef struct DL_INFO {
32 const char * dli_fname;
34 const char * dli_sname;
40 #define _RLD_DLADDR 14
41 int dladdr(void *address, Dl_info *dl);
43 int dladdr(void *address, Dl_info *dl)
46 v = _rld_new_interface(_RLD_DLADDR,address,dl);
51 extern gchar *_gst_progname;
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",
87 /* [GST_CAT_CALL_TRACE] = */ "CALL_TRACE",
92 * gst_get_category_name:
93 * @category: the category to return the name of
95 * Return a string containing the name of the category
97 * Returns: string containing the name of the category
100 gst_get_category_name (gint category) {
101 if ((category >= 0) && (category < GST_CAT_MAX_CATEGORY))
102 return _gst_info_category_strings[category];
110 * 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
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
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", /* !! */
148 /* [GST_CAT_CALL_TRACE] = */ "",
149 /* [31] = */ "05;31",
152 /* colorization hash - DEPRACATED in favor of above */
153 inline gint _gst_debug_stringhash_color(gchar *file) {
155 while (file[0]) filecolor += *(char *)(file++);
156 filecolor = (filecolor % 6) + 31;
161 /***** DEBUG system *****/
162 GstDebugHandler _gst_debug_handler = gst_default_debug_handler;
163 guint32 _gst_debug_categories = 0x00000000;
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
176 * Prints out the DEBUG mesage in a variant of the following form:
178 * DEBUG(pid:cid):gst_function:542(args): [elementname] something neat happened
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;
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)
194 gchar *elementname = empty,*location = empty;
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);
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));
209 elementname = g_strdup_printf (" [%s]", GST_OBJECT_NAME (element));
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);
218 fprintf(stderr,"DEBUG(%5d:%2d)%s%s %s\n",
219 pid,cothread_id,location,elementname,string);
220 #endif /* GST_DEBUG_COLOR */
222 if (location != empty) g_free(location);
223 if (elementname != empty) g_free(elementname);
230 * gst_debug_set_categories:
231 * @categories: bitmask of DEBUG categories to enable
233 * Enable the output of DEBUG categories based on the given bitmask.
234 * The bit for any given category is (1 << GST_CAT_...).
237 gst_debug_set_categories (guint32 categories) {
238 _gst_debug_categories = categories;
242 * gst_debug_get_categories:
244 * Return the current bitmask of enabled DEBUG categories
246 * Returns: the current bitmask of enabled DEBUG categories
247 * The bit for any given category is (1 << GST_CAT_...).
250 gst_debug_get_categories () {
251 return _gst_debug_categories;
255 * gst_debug_enable_category:
256 * @category: the category to enable
258 * Enables the given GST_CAT_... DEBUG category.
261 gst_debug_enable_category (gint category) {
262 _gst_debug_categories |= (1 << category);
266 * gst_debug_disable_category:
267 * @category: the category to disable
269 * Disables the given GST_CAT_... DEBUG category.
272 gst_debug_disable_category (gint category) {
273 _gst_debug_categories &= ~ (1 << category);
279 /***** INFO system *****/
280 GstInfoHandler _gst_info_handler = gst_default_info_handler;
281 guint32 _gst_info_categories = 0x00000001;
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
295 * Prints out the INFO mesage in a variant of the following form:
297 * INFO:gst_function:542(args): [elementname] something neat happened
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)
306 gchar *elementname = empty,*location = empty;
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);
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));
321 #ifdef GST_DEBUG_ENABLED
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);
329 fprintf(stderr,"INFO (%5d:%2d)%s%s %s\n",
330 pid,cothread_id,location,elementname,string);
331 #endif /* GST_DEBUG_COLOR */
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);
338 fprintf(stderr,"INFO:%s%s %s\n",
339 location,elementname,string);
340 #endif * GST_DEBUG_COLOR *
345 if (location != empty) g_free(location);
346 if (elementname != empty) g_free(elementname);
352 * gst_info_set_categories:
353 * @categories: bitmask of INFO categories to enable
355 * Enable the output of INFO categories based on the given bitmask.
356 * The bit for any given category is (1 << GST_CAT_...).
359 gst_info_set_categories (guint32 categories) {
360 _gst_info_categories = categories;
364 * gst_info_get_categories:
366 * Return the current bitmask of enabled INFO categories
367 * The bit for any given category is (1 << GST_CAT_...).
369 * Returns: the current bitmask of enabled INFO categories
370 * The bit for any given category is (1 << GST_CAT_...).
373 gst_info_get_categories () {
374 return _gst_info_categories;
378 * gst_info_enable_category:
379 * @category: the category to enable
381 * Enables the given GST_CAT_... INFO category.
384 gst_info_enable_category (gint category) {
385 _gst_info_categories |= (1 << category);
389 * gst_info_disable_category:
390 * @category: the category to disable
392 * Disables the given GST_CAT_... INFO category.
395 gst_info_disable_category (gint category) {
396 _gst_info_categories &= ~ (1 << category);
401 /***** ERROR system *****/
402 GstErrorHandler _gst_error_handler = gst_default_error_handler;
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
414 * Prints out the given ERROR string in a variant of the following format:
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.... *****
421 * At the end, it attempts to print the stack trace via GDB.
424 gst_default_error_handler (gchar *file, gchar *function,
425 gint line, gchar *debug_string,
426 void *element, void *object, gchar *string)
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 = "";
436 /* print out a preamble */
437 fprintf(stderr,"***** GStreamer ERROR ***** in file %s at %s:%d%s\n",
438 file,function,line,debug_string);
440 /* if there's an element, print out the pertinent information */
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);
448 fprintf(stderr,"Element ptr: %p",element);
449 chars = 15 + sizeof(void*)*2;
453 /* if there's an object, print it out as well */
455 /* attempt to pad the line, or create a new one */
457 for (i=0;i<(40-chars)/8+1;i++) fprintf(stderr,"\t");
459 fprintf(stderr,"\n");
461 if (GST_IS_OBJECT(object)) {
462 path = gst_object_get_path_string(object);
463 fprintf(stderr,"Object: %s",path);
466 fprintf(stderr,"Object ptr: %p",object);
470 fprintf(stderr,"\n");
471 fprintf(stderr,"Error: %s\n",string);
475 fprintf(stderr,"***** attempting to stack trace.... *****\n");
477 g_on_error_stack_trace (_gst_progname);
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; */
490 gchar *_gst_debug_nameof_funcptr (void *ptr) G_GNUC_NO_INSTRUMENT;
493 _gst_debug_nameof_funcptr (void *ptr)
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);
502 return g_strdup_printf("%p",ptr);
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)
513 gchar *name = _gst_debug_nameof_funcptr (this_fn);
514 gchar *site = _gst_debug_nameof_funcptr (call_site);
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));
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)
526 gchar *name = _gst_debug_nameof_funcptr (this_fn);
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);
536 gst_debug_print_stack_trace (void)
538 GSList *walk = stack_trace;
542 walk = g_slist_next (walk);
545 gchar *name = (gchar *) walk->data;
547 g_print ("#%-2d %s\n", count++, name);
549 walk = g_slist_next (walk);
554 gst_debug_print_stack_trace (void)
556 /* nothing because it's compiled out */
559 #endif /* GST_ENABLE_FUNC_INTSTRUMENTATION */