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;
53 GStaticPrivate _gst_debug_cothread_index = G_STATIC_PRIVATE_INIT;
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",
89 /* [GST_CAT_CALL_TRACE] = */ "CALL_TRACE",
94 * gst_get_category_name:
95 * @category: the category to return the name of
97 * Return a string containing the name of the category
99 * Returns: string containing the name of the category
102 gst_get_category_name (gint category) {
103 if ((category >= 0) && (category < GST_CAT_MAX_CATEGORY))
104 return _gst_info_category_strings[category];
112 * 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
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
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", /* !! */
150 /* [GST_CAT_CALL_TRACE] = */ "",
151 /* [31] = */ "05;31",
154 /* colorization hash - DEPRACATED in favor of above */
155 inline gint _gst_debug_stringhash_color(gchar *file) {
157 while (file[0]) filecolor += *(char *)(file++);
158 filecolor = (filecolor % 6) + 31;
163 /***** DEBUG system *****/
164 GstDebugHandler _gst_debug_handler = gst_default_debug_handler;
165 guint32 _gst_debug_categories = 0x00000000;
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
178 * Prints out the DEBUG mesage in a variant of the following form:
180 * DEBUG(pid:cid):gst_function:542(args): [elementname] something neat happened
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;
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)
196 gchar *elementname = empty,*location = empty;
198 int cothread_id = (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);
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));
213 elementname = g_strdup_printf (" [%s]", GST_OBJECT_NAME (element));
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);
222 fprintf(stderr,"DEBUG(%5d:%2d)%s%s %s\n",
223 pid, cothread_id, location, elementname, string);
224 #endif /* GST_DEBUG_COLOR */
226 if (location != empty) g_free (location);
227 if (elementname != empty) g_free (elementname);
234 * gst_debug_set_categories:
235 * @categories: bitmask of DEBUG categories to enable
237 * Enable the output of DEBUG categories based on the given bitmask.
238 * The bit for any given category is (1 << GST_CAT_...).
241 gst_debug_set_categories (guint32 categories) {
242 _gst_debug_categories = categories;
246 * gst_debug_get_categories:
248 * Return the current bitmask of enabled DEBUG categories
250 * Returns: the current bitmask of enabled DEBUG categories
251 * The bit for any given category is (1 << GST_CAT_...).
254 gst_debug_get_categories () {
255 return _gst_debug_categories;
259 * gst_debug_enable_category:
260 * @category: the category to enable
262 * Enables the given GST_CAT_... DEBUG category.
265 gst_debug_enable_category (gint category) {
266 _gst_debug_categories |= (1 << category);
270 * gst_debug_disable_category:
271 * @category: the category to disable
273 * Disables the given GST_CAT_... DEBUG category.
276 gst_debug_disable_category (gint category) {
277 _gst_debug_categories &= ~ (1 << category);
280 /***** INFO system *****/
281 GstInfoHandler _gst_info_handler = gst_default_info_handler;
282 guint32 _gst_info_categories = 0x00000001;
284 /* FIXME:what does debug_string DO ??? */
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
296 * Prints out the INFO mesage in a variant of the following form:
298 * FIXME: description should be fixed
299 * INFO:gst_function:542(args): [elementname] something neat happened
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)
308 gchar *elementname = empty,*location = empty;
310 int cothread_id = (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);
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));
325 #ifdef GST_DEBUG_ENABLED
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);
333 fprintf (stderr, "INFO (%5d:%2d)%s%s %s\n",
334 pid, cothread_id, location, elementname, string);
335 #endif /* GST_DEBUG_COLOR */
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);
342 fprintf(stderr,"INFO:%s%s %s\n",
343 location,elementname,string);
344 #endif * GST_DEBUG_COLOR *
349 if (location != empty) g_free (location);
350 if (elementname != empty) g_free (elementname);
356 * gst_info_set_categories:
357 * @categories: bitmask of INFO categories to enable
359 * Enable the output of INFO categories based on the given bitmask.
360 * The bit for any given category is (1 << GST_CAT_...).
363 gst_info_set_categories (guint32 categories) {
364 _gst_info_categories = categories;
368 * gst_info_get_categories:
370 * Return the current bitmask of enabled INFO categories
371 * The bit for any given category is (1 << GST_CAT_...).
373 * Returns: the current bitmask of enabled INFO categories
374 * The bit for any given category is (1 << GST_CAT_...).
377 gst_info_get_categories () {
378 return _gst_info_categories;
382 * gst_info_enable_category:
383 * @category: the category to enable
385 * Enables the given GST_CAT_... INFO category.
388 gst_info_enable_category (gint category) {
389 _gst_info_categories |= (1 << category);
393 * gst_info_disable_category:
394 * @category: the category to disable
396 * Disables the given GST_CAT_... INFO category.
399 gst_info_disable_category (gint category) {
400 _gst_info_categories &= ~ (1 << category);
405 /***** ERROR system *****/
406 GstErrorHandler _gst_error_handler = gst_default_error_handler;
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
418 * Prints out the given ERROR string in a variant of the following format:
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.... *****
425 * At the end, it attempts to print the stack trace via GDB.
428 gst_default_error_handler (gchar *file, gchar *function,
429 gint line, gchar *debug_string,
430 void *element, void *object, gchar *string)
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 = "";
440 /* print out a preamble */
441 fprintf(stderr,"***** GStreamer ERROR ***** in file %s at %s:%d%s\n",
442 file,function,line,debug_string);
444 /* if there's an element, print out the pertinent information */
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);
452 fprintf(stderr,"Element ptr: %p",element);
453 chars = 15 + sizeof(void*)*2;
457 /* if there's an object, print it out as well */
459 /* attempt to pad the line, or create a new one */
461 for (i=0;i<(40-chars)/8+1;i++) fprintf(stderr,"\t");
463 fprintf(stderr,"\n");
465 if (GST_IS_OBJECT(object)) {
466 path = gst_object_get_path_string(object);
467 fprintf(stderr,"Object: %s",path);
470 fprintf(stderr,"Object ptr: %p",object);
474 fprintf(stderr,"\n");
475 fprintf(stderr,"Error: %s\n",string);
479 fprintf(stderr,"***** attempting to stack trace.... *****\n");
481 g_on_error_stack_trace (_gst_progname);
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; */
495 gchar *_gst_debug_nameof_funcptr (void *ptr) G_GNUC_NO_INSTRUMENT;
498 _gst_debug_nameof_funcptr (void *ptr)
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);
507 return g_strdup_printf("%p",ptr);
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)
519 gchar *name = _gst_debug_nameof_funcptr (this_fn);
520 gchar *site = _gst_debug_nameof_funcptr (call_site);
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));
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)
532 gchar *name = _gst_debug_nameof_funcptr (this_fn);
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);
542 gst_debug_print_stack_trace (void)
544 GSList *walk = stack_trace;
548 walk = g_slist_next (walk);
551 gchar *name = (gchar *) walk->data;
553 g_print ("#%-2d %s\n", count++, name);
555 walk = g_slist_next (walk);
560 gst_debug_print_stack_trace (void)
562 /* nothing because it's compiled out */
565 #endif /* GST_ENABLE_FUNC_INTSTRUMENTATION */
568 _gst_debug_register_funcptr (void *ptr, gchar *ptrname)
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);