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 static gchar *_gst_info_category_strings[] = {
89 * gst_get_category_name:
90 * @category: the category to return the name of
92 * Return a string containing the name of the category
94 * Returns: string containing the name of the category
97 gst_get_category_name (gint category) {
98 if ((category >= 0) && (category < GST_CAT_MAX_CATEGORY))
99 return _gst_info_category_strings[category];
107 * 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
109 * 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
110 * Background color codes:
111 * 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
113 const gchar *_gst_category_colors[32] = {
114 [GST_CAT_GST_INIT] = "07;37",
115 [GST_CAT_COTHREADS] = "00;32",
116 [GST_CAT_COTHREAD_SWITCH] = "00;37;42",
117 [GST_CAT_AUTOPLUG] = "00;34",
118 [GST_CAT_AUTOPLUG_ATTEMPT] = "00;36;44",
119 [GST_CAT_PARENTAGE] = "01;37;41", /* !! */
120 [GST_CAT_STATES] = "00;31",
121 [GST_CAT_PLANNING] = "07;35",
122 [GST_CAT_SCHEDULING] = "00;35",
123 [GST_CAT_DATAFLOW] = "00;32",
124 [GST_CAT_BUFFER] = "00;32",
125 [GST_CAT_CAPS] = "04;34",
126 [GST_CAT_CLOCK] = "00;33", /* !! */
127 [GST_CAT_ELEMENT_PADS] = "01;37;41", /* !! */
128 [GST_CAT_ELEMENT_FACTORY] = "01;37;41", /* !! */
129 [GST_CAT_PADS] = "01;37;41", /* !! */
130 [GST_CAT_PIPELINE] = "01;37;41", /* !! */
131 [GST_CAT_PLUGIN_LOADING] = "00;36",
132 [GST_CAT_PLUGIN_ERRORS] = "05;31",
133 [GST_CAT_PLUGIN_INFO] = "00;36",
134 [GST_CAT_PROPERTIES] = "00;37;44", /* !! */
135 [GST_CAT_THREAD] = "00;31",
136 [GST_CAT_TYPES] = "01;37;41", /* !! */
137 [GST_CAT_XML] = "01;37;41", /* !! */
138 [GST_CAT_NEGOTIATION] = "07;34",
139 [GST_CAT_REFCOUNTING] = "00;34:42",
140 [GST_CAT_EVENT] = "01;37;41", /* !! */
141 [GST_CAT_PARAMS] = "00;30;43", /* !! */
143 [GST_CAT_CALL_TRACE] = "",
147 /* colorization hash - DEPRACATED in favor of above */
148 inline gint _gst_debug_stringhash_color(gchar *file) {
150 while (file[0]) filecolor += *(char *)(file++);
151 filecolor = (filecolor % 6) + 31;
157 /***** DEBUG system *****/
158 GstDebugHandler _gst_debug_handler = gst_default_debug_handler;
159 guint32 _gst_debug_categories = 0x00000000;
162 * gst_default_debug_handler:
163 * @category: category of the DEBUG message
164 * @incore: if the debug handler is for core code.
165 * @file: the file the DEBUG occurs in
166 * @function: the function the DEBUG occurs in
167 * @line: the line number in the file
168 * @debug_string: the current debug_string in the function, if any
169 * @element: pointer to the #GstElement in question
170 * @string: the actual DEBUG string
172 * Prints out the DEBUG mesage in a variant of the following form:
174 * DEBUG(pid:cid):gst_function:542(args): [elementname] something neat happened
177 gst_default_debug_handler (gint category, gboolean incore,
178 const gchar *file, const gchar *function,
179 gint line, const gchar *debug_string,
180 void *element, gchar *string)
181 __attribute__ ((no_instrument_function));
184 gst_default_debug_handler (gint category, gboolean incore,
185 const gchar *file, const gchar *function,
186 gint line, const gchar *debug_string,
187 void *element, gchar *string)
190 gchar *elementname = empty,*location = empty;
191 int pthread_id = getpid();
192 int cothread_id = 0; /*FIXME*/
193 #ifdef GST_DEBUG_COLOR
194 int pthread_color = pthread_id%6 + 31;
195 int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
198 if (debug_string == NULL) debug_string = "";
199 /* if (category != GST_CAT_GST_INIT) */
200 location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
201 if (element && GST_IS_ELEMENT (element))
202 #ifdef GST_DEBUG_COLOR
203 elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
205 elementname = g_strdup_printf (" [%s]", GST_OBJECT_NAME (element));
208 #ifdef GST_DEBUG_COLOR
209 fprintf(stderr,"DEBUG(\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
210 "%s;%sm%s%s\033[00m %s\n",
211 pthread_color,pthread_id,cothread_color,cothread_id,incore?"00":"01",
212 _gst_category_colors[category],location,elementname,string);
214 fprintf(stderr,"DEBUG(%5d:%2d)%s%s %s\n",
215 pthread_id,cothread_id,location,elementname,string);
216 #endif /* GST_DEBUG_COLOR */
218 if (location != empty) g_free(location);
219 if (elementname != empty) g_free(elementname);
226 * gst_debug_set_categories:
227 * @categories: bitmask of DEBUG categories to enable
229 * Enable the output of DEBUG categories based on the given bitmask.
230 * The bit for any given category is (1 << GST_CAT_...).
233 gst_debug_set_categories (guint32 categories) {
234 _gst_debug_categories = categories;
238 * gst_debug_get_categories:
240 * Return the current bitmask of enabled DEBUG categories
242 * Returns: the current bitmask of enabled DEBUG categories
243 * The bit for any given category is (1 << GST_CAT_...).
246 gst_debug_get_categories () {
247 return _gst_debug_categories;
251 * gst_debug_enable_category:
252 * @category: the category to enable
254 * Enables the given GST_CAT_... DEBUG category.
257 gst_debug_enable_category (gint category) {
258 _gst_debug_categories |= (1 << category);
262 * gst_debug_disable_category:
263 * @category: the category to disable
265 * Disables the given GST_CAT_... DEBUG category.
268 gst_debug_disable_category (gint category) {
269 _gst_debug_categories &= ~ (1 << category);
275 /***** INFO system *****/
276 GstInfoHandler _gst_info_handler = gst_default_info_handler;
277 guint32 _gst_info_categories = 0x00000001;
281 * gst_default_info_handler:
282 * @category: category of the INFO message
283 * @incore: if the info handler is for core code.
284 * @file: the file the INFO occurs in
285 * @function: the function the INFO occurs in
286 * @line: the line number in the file
287 * @debug_string: the current debug_string in the function, if any
288 * @element: pointer to the #GstElement in question
289 * @string: the actual INFO string
291 * Prints out the INFO mesage in a variant of the following form:
293 * INFO:gst_function:542(args): [elementname] something neat happened
296 gst_default_info_handler (gint category, gboolean incore,
297 const gchar *file, const gchar *function,
298 gint line, const gchar *debug_string,
299 void *element, gchar *string)
302 gchar *elementname = empty,*location = empty;
303 int pthread_id = getpid();
304 int cothread_id = 0; /*FIXME*/
305 #ifdef GST_DEBUG_COLOR
306 int pthread_color = pthread_id%6 + 31;
307 int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
310 if (debug_string == NULL) debug_string = "";
311 if (category != GST_CAT_GST_INIT)
312 location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
313 if (element && GST_IS_ELEMENT (element))
314 elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
317 #ifdef GST_DEBUG_ENABLED
319 #ifdef GST_DEBUG_COLOR
320 fprintf(stderr,"\033[01mINFO\033[00m (\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
321 GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
322 pthread_color,pthread_id,cothread_color,cothread_id,
323 _gst_category_colors[category],location,elementname,string);
325 fprintf(stderr,"INFO (%5d:%2d)%s%s %s\n",
326 pthread_id,cothread_id,location,elementname,string);
327 #endif /* GST_DEBUG_COLOR */
330 #ifdef GST_DEBUG_COLOR
331 fprintf(stderr,"\033[01mINFO\033[00m:\033[" GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
332 location,elementname,_gst_category_colors[category],string);
334 fprintf(stderr,"INFO:%s%s %s\n",
335 location,elementname,string);
336 #endif * GST_DEBUG_COLOR *
341 if (location != empty) g_free(location);
342 if (elementname != empty) g_free(elementname);
348 * gst_info_set_categories:
349 * @categories: bitmask of INFO categories to enable
351 * Enable the output of INFO categories based on the given bitmask.
352 * The bit for any given category is (1 << GST_CAT_...).
355 gst_info_set_categories (guint32 categories) {
356 _gst_info_categories = categories;
360 * gst_info_get_categories:
362 * Return the current bitmask of enabled INFO categories
363 * The bit for any given category is (1 << GST_CAT_...).
365 * Returns: the current bitmask of enabled INFO categories
366 * The bit for any given category is (1 << GST_CAT_...).
369 gst_info_get_categories () {
370 return _gst_info_categories;
374 * gst_info_enable_category:
375 * @category: the category to enable
377 * Enables the given GST_CAT_... INFO category.
380 gst_info_enable_category (gint category) {
381 _gst_info_categories |= (1 << category);
385 * gst_info_disable_category:
386 * @category: the category to disable
388 * Disables the given GST_CAT_... INFO category.
391 gst_info_disable_category (gint category) {
392 _gst_info_categories &= ~ (1 << category);
397 /***** ERROR system *****/
398 GstErrorHandler _gst_error_handler = gst_default_error_handler;
401 * gst_default_error_handler:
402 * @file: the file the ERROR occurs in
403 * @function: the function the INFO occurs in
404 * @line: the line number in the file
405 * @debug_string: the current debug_string in the function, if any
406 * @element: pointer to the #GstElement in question
407 * @object: pointer to a related object
408 * @string: the actual ERROR string
410 * Prints out the given ERROR string in a variant of the following format:
412 * ***** GStreamer ERROR ***** in file gstsomething.c at gst_function:399(arg)
413 * Element: /pipeline/thread/element.src
414 * Error: peer is null!
415 * ***** attempting to stack trace.... *****
417 * At the end, it attempts to print the stack trace via GDB.
420 gst_default_error_handler (gchar *file, gchar *function,
421 gint line, gchar *debug_string,
422 void *element, void *object, gchar *string)
428 /* if there are NULL pointers, point them to null strings to clean up output */
429 if (!debug_string) debug_string = "";
430 if (!string) string = "";
432 /* print out a preamble */
433 fprintf(stderr,"***** GStreamer ERROR ***** in file %s at %s:%d%s\n",
434 file,function,line,debug_string);
436 /* if there's an element, print out the pertinent information */
438 if (GST_IS_OBJECT(element)) {
439 path = gst_object_get_path_string(element);
440 fprintf(stderr,"Element: %s",path);
441 chars = 9 + strlen(path);
444 fprintf(stderr,"Element ptr: %p",element);
445 chars = 15 + sizeof(void*)*2;
449 /* if there's an object, print it out as well */
451 /* attempt to pad the line, or create a new one */
453 for (i=0;i<(40-chars)/8+1;i++) fprintf(stderr,"\t");
455 fprintf(stderr,"\n");
457 if (GST_IS_OBJECT(object)) {
458 path = gst_object_get_path_string(object);
459 fprintf(stderr,"Object: %s",path);
462 fprintf(stderr,"Object ptr: %p",object);
466 fprintf(stderr,"\n");
467 fprintf(stderr,"Error: %s\n",string);
471 fprintf(stderr,"***** attempting to stack trace.... *****\n");
473 g_on_error_stack_trace (_gst_progname);
480 /***** DEBUG system *****/
481 GHashTable *__gst_function_pointers = NULL;
482 /* FIXME make this thread specific */
483 /* static GSList *stack_trace = NULL; */
485 gchar *_gst_debug_nameof_funcptr (void *ptr) __attribute__ ((no_instrument_function));
488 _gst_debug_nameof_funcptr (void *ptr)
492 if (__gst_function_pointers && (ptrname = g_hash_table_lookup(__gst_function_pointers,ptr))) {
493 return g_strdup(ptrname);
494 } else if (dladdr(ptr,&dlinfo) && dlinfo.dli_sname) {
495 return g_strdup(dlinfo.dli_sname);
497 return g_strdup_printf("%p",ptr);
503 #ifdef GST_ENABLE_FUNC_INSTRUMENTATION
504 void __cyg_profile_func_enter(void *this_fn,void *call_site) __attribute__ ((no_instrument_function));
505 void __cyg_profile_func_enter(void *this_fn,void *call_site)
507 gchar *name = _gst_debug_nameof_funcptr (this_fn);
508 gchar *site = _gst_debug_nameof_funcptr (call_site);
510 GST_DEBUG(GST_CAT_CALL_TRACE, "entering function %s from %s", name, site);
511 stack_trace = g_slist_prepend (stack_trace, g_strdup_printf ("%8p in %s from %p (%s)", this_fn, name, call_site, site));
517 void __cyg_profile_func_exit(void *this_fn,void *call_site) __attribute__ ((no_instrument_function));
518 void __cyg_profile_func_exit(void *this_fn,void *call_site)
520 gchar *name = _gst_debug_nameof_funcptr (this_fn);
522 GST_DEBUG(GST_CAT_CALL_TRACE, "leaving function %s", name);
523 g_free (stack_trace->data);
524 stack_trace = g_slist_delete_link (stack_trace, stack_trace);
530 gst_debug_print_stack_trace (void)
532 GSList *walk = stack_trace;
536 walk = g_slist_next (walk);
539 gchar *name = (gchar *) walk->data;
541 g_print ("#%-2d %s\n", count++, name);
543 walk = g_slist_next (walk);
548 gst_debug_print_stack_trace (void)
550 /* nothing because it's compiled out */
553 #endif /* GST_ENABLE_FUNC_INTSTRUMENTATION */