mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 01:00:37 +00:00
gst: add some gdb python macros
This adds gdb pretty printer for some GStreamer types. For GstObject pointers the type and name is added, e.g. "0x5555557e4110 [GstDecodeBin|decodebin0]". For GstMiniObject pointers the object type is added, e.g. "0x7fffe001fc50 [GstBuffer]". For GstClockTime and GstClockTimeDiff the time is also printed in human readable form, e.g. "150116219955 [+0:02:30.116219955]". Fixes #320
This commit is contained in:
parent
1fda8c3bcf
commit
bc621cc335
7 changed files with 226 additions and 0 deletions
|
@ -1083,6 +1083,7 @@ data/bash-completion/helpers/gst
|
|||
gst/Makefile
|
||||
gst/gstconfig.h
|
||||
gst/gstversion.h
|
||||
libs/gst/helpers/libgstreamer-gdb.py
|
||||
gst/parse/Makefile
|
||||
gst/printf/Makefile
|
||||
libs/Makefile
|
||||
|
|
1
libs/gst/helpers/.gitignore
vendored
1
libs/gst/helpers/.gitignore
vendored
|
@ -1,4 +1,5 @@
|
|||
gst-plugin-scanner
|
||||
gst-completion-helper
|
||||
gst-ptp-helper
|
||||
libgstreamer-gdb.py
|
||||
*.o
|
||||
|
|
|
@ -31,3 +31,10 @@ endif
|
|||
endif
|
||||
|
||||
EXTRA_DIST = ptp_helper_post_install.sh
|
||||
|
||||
# install gdb scripts
|
||||
gdbdir = $(datadir)/gstreamer-@GST_API_VERSION@/gdb
|
||||
dist_gdb_DATA = gst_gdb.py glib_gobject_helper.py
|
||||
|
||||
install-data-hook:
|
||||
$(INSTALL) -D $(builddir)/libgstreamer-gdb.py $(DESTDIR)$(datadir)/gdb/auto-load$(libdir)/libgstreamer-@GST_API_VERSION@.so.0.$(GST_CURRENT).$(GST_REVISION)-gdb.py
|
||||
|
|
70
libs/gst/helpers/glib_gobject_helper.py
Normal file
70
libs/gst/helpers/glib_gobject_helper.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
##
|
||||
## imported from glib: glib/glib_gdb.py
|
||||
##
|
||||
import gdb
|
||||
import sys
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
long = int
|
||||
|
||||
# This is not quite right, as local vars may override symname
|
||||
def read_global_var (symname):
|
||||
return gdb.selected_frame().read_var(symname)
|
||||
|
||||
def g_quark_to_string (quark):
|
||||
if quark is None:
|
||||
return None
|
||||
quark = long(quark)
|
||||
if quark == 0:
|
||||
return None
|
||||
try:
|
||||
val = read_global_var ("quarks")
|
||||
max_q = long(read_global_var ("quark_seq_id"))
|
||||
except:
|
||||
try:
|
||||
val = read_global_var ("g_quarks")
|
||||
max_q = long(read_global_var ("g_quark_seq_id"))
|
||||
except:
|
||||
return None;
|
||||
if quark < max_q:
|
||||
return val[quark].string()
|
||||
return None
|
||||
|
||||
##
|
||||
## imported from glib: gobject/gobject_gdb.py
|
||||
##
|
||||
|
||||
def g_type_to_typenode (gtype):
|
||||
def lookup_fundamental_type (typenode):
|
||||
if typenode == 0:
|
||||
return None
|
||||
val = read_global_var ("static_fundamental_type_nodes")
|
||||
if val is None:
|
||||
return None
|
||||
return val[typenode >> 2].address
|
||||
|
||||
gtype = long(gtype)
|
||||
typenode = gtype - gtype % 4
|
||||
if typenode > (255 << 2):
|
||||
typenode = gdb.Value(typenode).cast (gdb.lookup_type("TypeNode").pointer())
|
||||
else:
|
||||
typenode = lookup_fundamental_type (typenode)
|
||||
return typenode
|
||||
|
||||
def g_type_to_name (gtype):
|
||||
typenode = g_type_to_typenode(gtype)
|
||||
if typenode != None:
|
||||
return g_quark_to_string (typenode["qname"])
|
||||
return None
|
||||
|
||||
def g_type_name_from_instance (instance):
|
||||
if long(instance) != 0:
|
||||
try:
|
||||
inst = instance.cast (gdb.lookup_type("GTypeInstance").pointer())
|
||||
klass = inst["g_class"]
|
||||
gtype = klass["g_type"]
|
||||
name = g_type_to_name (gtype)
|
||||
return name
|
||||
except RuntimeError:
|
||||
pass
|
||||
return None
|
116
libs/gst/helpers/gst_gdb.py
Normal file
116
libs/gst/helpers/gst_gdb.py
Normal file
|
@ -0,0 +1,116 @@
|
|||
import gdb
|
||||
import sys
|
||||
import re
|
||||
|
||||
from glib_gobject_helper import g_type_to_name, g_type_name_from_instance
|
||||
|
||||
if sys.version_info[0] >= 3:
|
||||
long = int
|
||||
|
||||
def is_gst_type (val, klass):
|
||||
def _is_gst_type (type):
|
||||
if str(type) == klass:
|
||||
return True
|
||||
|
||||
while type.code == gdb.TYPE_CODE_TYPEDEF:
|
||||
type = type.target()
|
||||
|
||||
if type.code != gdb.TYPE_CODE_STRUCT:
|
||||
return False
|
||||
|
||||
fields = type.fields()
|
||||
if len (fields) < 1:
|
||||
return False
|
||||
|
||||
first_field = fields[0]
|
||||
return _is_gst_type (first_field.type)
|
||||
|
||||
|
||||
type = val.type
|
||||
if type.code != gdb.TYPE_CODE_PTR:
|
||||
return False
|
||||
type = type.target()
|
||||
return _is_gst_type (type)
|
||||
|
||||
class GstMiniObjectPrettyPrinter:
|
||||
"Prints a GstMiniObject instance pointer"
|
||||
|
||||
def __init__ (self, val):
|
||||
self.val = val
|
||||
|
||||
def to_string (self):
|
||||
try:
|
||||
inst = self.val.cast (gdb.lookup_type("GstMiniObject").pointer())
|
||||
gtype = inst["type"]
|
||||
name = g_type_to_name (gtype)
|
||||
return "0x%x [%s]" % (long(self.val), name)
|
||||
except RuntimeError:
|
||||
return "0x%x" % long(self.val)
|
||||
|
||||
class GstObjectPrettyPrinter:
|
||||
"Prints a GstObject instance"
|
||||
|
||||
def __init__ (self, val):
|
||||
self.val = val
|
||||
|
||||
def to_string (self):
|
||||
try:
|
||||
name = g_type_name_from_instance (self.val)
|
||||
if not name:
|
||||
name = str(self.val.type.target())
|
||||
if long(self.val) != 0:
|
||||
inst = self.val.cast (gdb.lookup_type("GstObject").pointer())
|
||||
inst_name = inst["name"].string()
|
||||
if inst_name:
|
||||
name += "|" + inst_name
|
||||
return ("0x%x [%s]") % (long(self.val), name)
|
||||
except RuntimeError:
|
||||
return "0x%x" % long(self.val)
|
||||
|
||||
class GstClockTimePrinter:
|
||||
"Prints a GstClockTime / GstClockTimeDiff"
|
||||
|
||||
def __init__ (self, val):
|
||||
self.val = val
|
||||
|
||||
def to_string (self):
|
||||
GST_SECOND = 1000000000
|
||||
GST_CLOCK_TIME_NONE = 2**64-1
|
||||
GST_CLOCK_STIME_NONE = -2**63
|
||||
n = int(self.val)
|
||||
prefix = ""
|
||||
invalid = False
|
||||
if str(self.val.type) == "GstClockTimeDiff":
|
||||
if n == GST_CLOCK_STIME_NONE:
|
||||
invalid = True
|
||||
prefix = "+" if n >= 0 else "-"
|
||||
n = abs(n)
|
||||
else:
|
||||
if n == GST_CLOCK_TIME_NONE:
|
||||
invalid = True
|
||||
|
||||
if invalid:
|
||||
return str(n) + " [99:99:99.999999999]"
|
||||
|
||||
return str(n) + " [%s%u:%02u:%02u.%09u]" % ( prefix,
|
||||
n / (GST_SECOND * 60 * 60),
|
||||
(n / (GST_SECOND * 60)) % 60,
|
||||
(n / GST_SECOND) % 60,
|
||||
n % GST_SECOND )
|
||||
|
||||
def gst_pretty_printer_lookup (val):
|
||||
if is_gst_type (val, "GstMiniObject"):
|
||||
return GstMiniObjectPrettyPrinter (val)
|
||||
if is_gst_type (val, "GstObject"):
|
||||
return GstObjectPrettyPrinter (val)
|
||||
if str(val.type) == "GstClockTime" or str(val.type) == "GstClockTimeDiff":
|
||||
return GstClockTimePrinter (val)
|
||||
return None
|
||||
|
||||
def register (obj):
|
||||
if obj == None:
|
||||
obj = gdb
|
||||
|
||||
# Make sure this is always used befor the glib lookup function.
|
||||
# Otherwise the gobject pretty printer is used for GstObjects
|
||||
obj.pretty_printers.insert(0, gst_pretty_printer_lookup)
|
10
libs/gst/helpers/libgstreamer-gdb.py.in
Normal file
10
libs/gst/helpers/libgstreamer-gdb.py.in
Normal file
|
@ -0,0 +1,10 @@
|
|||
import sys
|
||||
import gdb
|
||||
|
||||
# Update module path.
|
||||
dir_ = '@DATADIR@/gstreamer-@GST_API_VERSION@/gdb'
|
||||
if not dir_ in sys.path:
|
||||
sys.path.insert(0, dir_)
|
||||
|
||||
from gst_gdb import register
|
||||
register (gdb.current_objfile ())
|
|
@ -124,3 +124,24 @@ if have_ptp
|
|||
helpers_install_dir, with_ptp_helper_permissions,
|
||||
setcap.found() ? setcap.path() : '')
|
||||
endif
|
||||
|
||||
install_data(['gst_gdb.py', 'glib_gobject_helper.py'],
|
||||
install_dir : join_paths(get_option('datadir'), 'glib-2.0', 'gdb'))
|
||||
|
||||
gdbconf = configuration_data()
|
||||
gdbconf.set('GST_API_VERSION', apiversion)
|
||||
gdbconf.set('DATADIR', '@0@/@1@'.format(get_option('prefix'), get_option('datadir')))
|
||||
|
||||
if host_system != 'windows'
|
||||
# XXX: We add a leading './' because prefix is an absolute path and we
|
||||
# need it to be a relative path so that join_paths appends it to the end.
|
||||
gdb_install_dir = join_paths(get_option('datadir'), 'gdb', 'auto-load', './' + get_option('prefix'), get_option('libdir'))
|
||||
else
|
||||
# FIXME: Cannot install on Windows because the path will contain a drive
|
||||
# letter and colons are not allowed in paths.
|
||||
gdb_install_dir = disabler()
|
||||
endif
|
||||
configure_file(input : 'libgstreamer-gdb.py.in',
|
||||
output : 'libgstreamer-@0@.so.@1@-gdb.py'.format(apiversion, libversion),
|
||||
install_dir : gdb_install_dir,
|
||||
configuration : gdbconf)
|
||||
|
|
Loading…
Reference in a new issue