gstinfo.c 15 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* GStreamer
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
 *                    2000 Wim Taymans <wtay@chello.be>
 *
 * gstinfo.c: INFO, ERROR, and DEBUG systems
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

23
#include <dlfcn.h>
24
#include "gst_private.h"
25
26
#include "gstelement.h"
#include "gstpad.h"
27
#include "gstscheduler.h"
28

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#if defined __sgi__
#include <rld_interface.h>
typedef struct DL_INFO {
  const char * dli_fname;
  void       * dli_fbase;
  const char * dli_sname;
  void       * dli_saddr;
  int          dli_version;
  int          dli_reserved1;
  long         dli_reserved[4];
} Dl_info;
#define _RLD_DLADDR             14
int dladdr(void *address, Dl_info *dl);

int dladdr(void *address, Dl_info *dl)
{
  void *v;
  v = _rld_new_interface(_RLD_DLADDR,address,dl);
  return (int)v;
}
#endif

51
52
53
extern gchar *_gst_progname;


54
/***** Categories and colorization *****/
55
56
57
58
59
60
61
62
static gchar *_gst_info_category_strings[] = {
  "GST_INIT",
  "COTHREADS",
  "COTHREAD_SWITCH",
  "AUTOPLUG",
  "AUTOPLUG_ATTEMPT",
  "PARENTAGE",
  "STATES",
63
  "PLANNING",
64
  "SCHEDULING",
65
  "DATAFLOW",
66
67
68
69
70
71
72
73
74
  "BUFFER",
  "CAPS",
  "CLOCK",
  "ELEMENT_PADS",
  "ELEMENTFACTORY",
  "PADS",
  "PIPELINE",
  "PLUGIN_LOADING",
  "PLUGIN_ERRORS",
75
  "PLUGIN_INFO",
76
77
78
79
  "PROPERTIES",
  "THREAD",
  "TYPES",
  "XML",
80
  "NEGOTIATION",
81
  "REFCOUNTING",
82
  "EVENT",
Steve Baker Baker's avatar
Steve Baker Baker committed
83
  "PARAMS",
84
85

  [30] = "CALL_TRACE",
86
};
87

88
89
90
91
/**
 * gst_get_category_name:
 * @category: the category to return the name of
 *
92
93
 * Return a string containing the name of the category
 *
94
95
96
97
98
99
100
101
102
103
 * Returns: string containing the name of the category
 */
const gchar *
gst_get_category_name (gint category) {
  if ((category >= 0) && (category < GST_CAT_MAX_CATEGORY))
    return _gst_info_category_strings[category];
  else
    return NULL;
}

104

105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
 * Attribute codes:
 * 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
 * Text color codes:
 * 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
 * Background color codes:
 * 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
 */
const gchar *_gst_category_colors[32] = {
  [GST_CAT_GST_INIT]		= "07;37",
  [GST_CAT_COTHREADS]		= "00;32",
  [GST_CAT_COTHREAD_SWITCH]	= "00;37;42",
  [GST_CAT_AUTOPLUG]		= "00;34",
  [GST_CAT_AUTOPLUG_ATTEMPT]	= "00;36;44",
119
  [GST_CAT_PARENTAGE]		= "01;37;41",		/* !! */
120
121
122
123
124
125
  [GST_CAT_STATES]		= "00;31",
  [GST_CAT_PLANNING]		= "07;35",
  [GST_CAT_SCHEDULING]		= "00;35",
  [GST_CAT_DATAFLOW]		= "00;32",
  [GST_CAT_BUFFER]		= "00;32",
  [GST_CAT_CAPS]		= "04;34",
126
127
  [GST_CAT_CLOCK]		= "00;33",		/* !! */
  [GST_CAT_ELEMENT_PADS]	= "01;37;41",		/* !! */
128
  [GST_CAT_ELEMENT_FACTORY]	= "01;37;41",		/* !! */
129
130
  [GST_CAT_PADS]		= "01;37;41",		/* !! */
  [GST_CAT_PIPELINE]		= "01;37;41",		/* !! */
131
132
133
  [GST_CAT_PLUGIN_LOADING]	= "00;36",
  [GST_CAT_PLUGIN_ERRORS]	= "05;31",
  [GST_CAT_PLUGIN_INFO]		= "00;36",
134
  [GST_CAT_PROPERTIES]		= "00;37;44",		/* !! */
135
  [GST_CAT_THREAD]		= "00;31",
136
137
  [GST_CAT_TYPES]		= "01;37;41",		/* !! */
  [GST_CAT_XML]			= "01;37;41",		/* !! */
138
139
  [GST_CAT_NEGOTIATION]		= "07;34",
  [GST_CAT_REFCOUNTING]		= "00;34:42",
140
141
  [GST_CAT_EVENT]		= "01;37;41",		/* !! */
  [GST_CAT_PARAMS]		= "00;30;43",		/* !! */
142

143
  [GST_CAT_CALL_TRACE]		= "",
144
  [31]				= "05;31",
145
};
146

147
/* colorization hash - DEPRACATED in favor of above */
148
inline gint _gst_debug_stringhash_color(gchar *file) {
149
  int filecolor = 0;
150
151
152
153
154
155
  while (file[0]) filecolor += *(char *)(file++);
  filecolor = (filecolor % 6) + 31;
  return filecolor;
}


156
157
158
159
160
161
162
163

/***** DEBUG system *****/
GstDebugHandler _gst_debug_handler = gst_default_debug_handler;
guint32 _gst_debug_categories = 0x00000000;

/**
 * gst_default_debug_handler:
 * @category: category of the DEBUG message
Wim Taymans's avatar
Wim Taymans committed
164
 * @incore: if the debug handler is for core code.
165
166
167
168
169
170
171
172
173
174
175
176
 * @file: the file the DEBUG occurs in
 * @function: the function the DEBUG occurs in
 * @line: the line number in the file
 * @debug_string: the current debug_string in the function, if any
 * @element: pointer to the #GstElement in question
 * @string: the actual DEBUG string
 *
 * Prints out the DEBUG mesage in a variant of the following form:
 *
 *   DEBUG(pid:cid):gst_function:542(args): [elementname] something neat happened
 */
void
177
178
179
180
181
182
183
gst_default_debug_handler (gint category, gboolean incore,
			   const gchar *file, const gchar *function,
			   gint line, const gchar *debug_string,
			   void *element, gchar *string)
  __attribute__ ((no_instrument_function));

void
184
185
186
187
gst_default_debug_handler (gint category, gboolean incore,
			   const gchar *file, const gchar *function,
			   gint line, const gchar *debug_string,
			   void *element, gchar *string)
188
189
190
{
  gchar *empty = "";
  gchar *elementname = empty,*location = empty;
191
  int pid = getpid();
192
  int cothread_id = 0; /*FIXME*/
193
#ifdef GST_DEBUG_COLOR
194
  int pid_color = pid%6 + 31;
195
196
197
198
  int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
#endif

  if (debug_string == NULL) debug_string = "";
199
/*  if (category != GST_CAT_GST_INIT) */
200
201
202
203
204
205
206
207
208
209
    location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
  if (element && GST_IS_ELEMENT (element))
#ifdef GST_DEBUG_COLOR
    elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
#else
    elementname = g_strdup_printf (" [%s]", GST_OBJECT_NAME (element));
#endif

#ifdef GST_DEBUG_COLOR
  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
          pid_color,pid,cothread_color,cothread_id,incore?"00":"01",
212
213
          _gst_category_colors[category],location,elementname,string);
#else
214
  fprintf(stderr,"DEBUG(%5d:%2d)%s%s %s\n",
215
          pid,cothread_id,location,elementname,string);
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
#endif /* GST_DEBUG_COLOR */

  if (location != empty) g_free(location);
  if (elementname != empty) g_free(elementname);

  g_free(string);
}


/**
 * gst_debug_set_categories:
 * @categories: bitmask of DEBUG categories to enable
 *
 * Enable the output of DEBUG categories based on the given bitmask.
 * The bit for any given category is (1 << GST_CAT_...).
 */
void
gst_debug_set_categories (guint32 categories) {
  _gst_debug_categories = categories;
}

/**
 * gst_debug_get_categories:
 *
240
241
 * Return the current bitmask of enabled DEBUG categories
 *
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
 * Returns: the current bitmask of enabled DEBUG categories
 * The bit for any given category is (1 << GST_CAT_...).
 */
guint32
gst_debug_get_categories () {
  return _gst_debug_categories;
}

/**
 * gst_debug_enable_category:
 * @category: the category to enable
 *
 * Enables the given GST_CAT_... DEBUG category.
 */
void
gst_debug_enable_category (gint category) {
  _gst_debug_categories |= (1 << category);
}

/**
 * gst_debug_disable_category:
 * @category: the category to disable
 *
 * Disables the given GST_CAT_... DEBUG category.
 */
void
gst_debug_disable_category (gint category) {
  _gst_debug_categories &= ~ (1 << category);
}




/***** INFO system *****/
GstInfoHandler _gst_info_handler = gst_default_info_handler;
guint32 _gst_info_categories = 0x00000001;


Erik Walthinsen's avatar
Erik Walthinsen committed
280
281
282
/**
 * gst_default_info_handler:
 * @category: category of the INFO message
Wim Taymans's avatar
Wim Taymans committed
283
 * @incore: if the info handler is for core code.
Erik Walthinsen's avatar
Erik Walthinsen committed
284
285
286
287
288
289
290
291
292
293
294
 * @file: the file the INFO occurs in
 * @function: the function the INFO occurs in
 * @line: the line number in the file
 * @debug_string: the current debug_string in the function, if any
 * @element: pointer to the #GstElement in question
 * @string: the actual INFO string
 *
 * Prints out the INFO mesage in a variant of the following form:
 *
 *   INFO:gst_function:542(args): [elementname] something neat happened
 */
295
void
296
297
298
299
gst_default_info_handler (gint category, gboolean incore,
			  const gchar *file, const gchar *function,
			  gint line, const gchar *debug_string,
			  void *element, gchar *string)
300
{
301
302
  gchar *empty = "";
  gchar *elementname = empty,*location = empty;
303
  int pid = getpid();
304
  int cothread_id = 0; /*FIXME*/
305
#ifdef GST_DEBUG_COLOR
306
  int pid_color = pid%6 + 31;
307
308
  int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
#endif
309
310

  if (debug_string == NULL) debug_string = "";
311
  if (category != GST_CAT_GST_INIT)
312
313
    location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
  if (element && GST_IS_ELEMENT (element))
314
    elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
315

316
/*
317
#ifdef GST_DEBUG_ENABLED
318
*/
319
  #ifdef GST_DEBUG_COLOR
320
321
    fprintf(stderr,"\033[01mINFO\033[00m (\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
            GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
322
            pid_color,pid,cothread_color,cothread_id,
323
            _gst_category_colors[category],location,elementname,string);
324
  #else
325
    fprintf(stderr,"INFO (%5d:%2d)%s%s %s\n",
326
            pid,cothread_id,location,elementname,string);
327
#endif /* GST_DEBUG_COLOR */
328
/*
329
#else
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
333
334
335
            location,elementname,_gst_category_colors[category],string);
  #else
    fprintf(stderr,"INFO:%s%s %s\n",
            location,elementname,string);
336
  #endif * GST_DEBUG_COLOR *
337

338
#endif
339
*/
340
341
342

  if (location != empty) g_free(location);
  if (elementname != empty) g_free(elementname);
343
344
345
346

  g_free(string);
}

Erik Walthinsen's avatar
Erik Walthinsen committed
347
348
349
350
351
352
353
/**
 * gst_info_set_categories:
 * @categories: bitmask of INFO categories to enable
 *
 * Enable the output of INFO categories based on the given bitmask.
 * The bit for any given category is (1 << GST_CAT_...).
 */
354
355
356
357
void
gst_info_set_categories (guint32 categories) {
  _gst_info_categories = categories;
}
358

Erik Walthinsen's avatar
Erik Walthinsen committed
359
360
361
/**
 * gst_info_get_categories:
 *
362
363
364
 * Return the current bitmask of enabled INFO categories
 * The bit for any given category is (1 << GST_CAT_...).
 *
Erik Walthinsen's avatar
Erik Walthinsen committed
365
366
367
 * Returns: the current bitmask of enabled INFO categories
 * The bit for any given category is (1 << GST_CAT_...).
 */
368
369
370
371
guint32
gst_info_get_categories () {
  return _gst_info_categories;
}
372

Erik Walthinsen's avatar
Erik Walthinsen committed
373
374
375
376
377
378
/**
 * gst_info_enable_category:
 * @category: the category to enable
 *
 * Enables the given GST_CAT_... INFO category.
 */
379
380
381
382
383
void
gst_info_enable_category (gint category) {
  _gst_info_categories |= (1 << category);
}

Erik Walthinsen's avatar
Erik Walthinsen committed
384
385
386
387
388
389
/**
 * gst_info_disable_category:
 * @category: the category to disable
 *
 * Disables the given GST_CAT_... INFO category.
 */
390
391
392
393
394
void
gst_info_disable_category (gint category) {
  _gst_info_categories &= ~ (1 << category);
}

395
396


397
398
/***** ERROR system *****/
GstErrorHandler _gst_error_handler = gst_default_error_handler;
399

Erik Walthinsen's avatar
Erik Walthinsen committed
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
/**
 * gst_default_error_handler:
 * @file: the file the ERROR occurs in
 * @function: the function the INFO occurs in
 * @line: the line number in the file
 * @debug_string: the current debug_string in the function, if any
 * @element: pointer to the #GstElement in question
 * @object: pointer to a related object
 * @string: the actual ERROR string
 *
 * Prints out the given ERROR string in a variant of the following format:
 *
 * ***** GStreamer ERROR ***** in file gstsomething.c at gst_function:399(arg)
 * Element: /pipeline/thread/element.src
 * Error: peer is null!
 * ***** attempting to stack trace.... *****
 *
 * At the end, it attempts to print the stack trace via GDB.
 */
419
420
421
422
423
424
425
426
427
void
gst_default_error_handler (gchar *file, gchar *function,
                           gint line, gchar *debug_string,
                           void *element, void *object, gchar *string)
{
  int chars = 0;
  gchar *path;
  int i;

428
  /* if there are NULL pointers, point them to null strings to clean up output */
429
430
431
  if (!debug_string) debug_string = "";
  if (!string) string = "";

432
  /* print out a preamble */
433
434
435
  fprintf(stderr,"***** GStreamer ERROR ***** in file %s at %s:%d%s\n",
          file,function,line,debug_string);

436
  /* if there's an element, print out the pertinent information */
437
  if (element) {
438
    if (GST_IS_OBJECT(element)) {
439
440
441
442
443
444
445
446
447
448
      path = gst_object_get_path_string(element);
      fprintf(stderr,"Element: %s",path);
      chars = 9 + strlen(path);
      g_free(path);
    } else {
      fprintf(stderr,"Element ptr: %p",element);
      chars = 15 + sizeof(void*)*2;
    }
  }

449
  /* if there's an object, print it out as well */
450
  if (object) {
451
    /* attempt to pad the line, or create a new one */
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
    if (chars < 40)
      for (i=0;i<(40-chars)/8+1;i++) fprintf(stderr,"\t");
    else
      fprintf(stderr,"\n");

    if (GST_IS_OBJECT(object)) {
      path = gst_object_get_path_string(object);
      fprintf(stderr,"Object: %s",path);
      g_free(path);
    } else {
      fprintf(stderr,"Object ptr: %p",object);
    }
  }

  fprintf(stderr,"\n");
  fprintf(stderr,"Error: %s\n",string);

  g_free(string);

  fprintf(stderr,"***** attempting to stack trace.... *****\n");

  g_on_error_stack_trace (_gst_progname);

  exit(1);
}
477
478
479
480
481



/***** DEBUG system *****/
GHashTable *__gst_function_pointers = NULL;
482
/* FIXME make this thread specific */
483
/* static GSList *stack_trace = NULL; */
484

485
486
gchar *_gst_debug_nameof_funcptr (void *ptr) __attribute__ ((no_instrument_function));

487
488
489
490
491
gchar *
_gst_debug_nameof_funcptr (void *ptr)
{
  gchar *ptrname;
  Dl_info dlinfo;
492
493
  if (__gst_function_pointers && (ptrname = g_hash_table_lookup(__gst_function_pointers,ptr))) {
    return g_strdup(ptrname);
494
495
496
497
498
499
500
  } else if (dladdr(ptr,&dlinfo) && dlinfo.dli_sname) {
    return g_strdup(dlinfo.dli_sname);
  } else {
    return g_strdup_printf("%p",ptr);
  }
  return NULL;
}
501
502
503
504


#ifdef GST_ENABLE_FUNC_INSTRUMENTATION
void __cyg_profile_func_enter(void *this_fn,void *call_site) __attribute__ ((no_instrument_function));
505
506
507
508
509
void __cyg_profile_func_enter(void *this_fn,void *call_site) 
{
  gchar *name = _gst_debug_nameof_funcptr (this_fn);
  gchar *site = _gst_debug_nameof_funcptr (call_site);
	
510
  GST_DEBUG(GST_CAT_CALL_TRACE, "entering function %s from %s", name, site);
511
512
513
514
  stack_trace = g_slist_prepend (stack_trace, g_strdup_printf ("%8p in %s from %p (%s)", this_fn, name, call_site, site));

  g_free (name);
  g_free (site);
515
516
517
}

void __cyg_profile_func_exit(void *this_fn,void *call_site) __attribute__ ((no_instrument_function));
518
519
520
521
void __cyg_profile_func_exit(void *this_fn,void *call_site) 
{
  gchar *name = _gst_debug_nameof_funcptr (this_fn);

522
  GST_DEBUG(GST_CAT_CALL_TRACE, "leaving function %s", name);
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
  g_free (stack_trace->data);
  stack_trace = g_slist_delete_link (stack_trace, stack_trace);

  g_free (name);
}

void 
gst_debug_print_stack_trace (void)
{
  GSList *walk = stack_trace;
  gint count = 0;

  if (walk)
    walk = g_slist_next (walk);

  while (walk) {
    gchar *name = (gchar *) walk->data;

    g_print ("#%-2d %s\n", count++, name);

    walk = g_slist_next (walk);
  }
}
#else
void 
gst_debug_print_stack_trace (void)
{
550
  /* nothing because it's compiled out */
551
552
553
}

#endif /* GST_ENABLE_FUNC_INTSTRUMENTATION */