mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-06 23:48:53 +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/Makefile
|
||||||
gst/gstconfig.h
|
gst/gstconfig.h
|
||||||
gst/gstversion.h
|
gst/gstversion.h
|
||||||
|
libs/gst/helpers/libgstreamer-gdb.py
|
||||||
gst/parse/Makefile
|
gst/parse/Makefile
|
||||||
gst/printf/Makefile
|
gst/printf/Makefile
|
||||||
libs/Makefile
|
libs/Makefile
|
||||||
|
|
1
libs/gst/helpers/.gitignore
vendored
1
libs/gst/helpers/.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
gst-plugin-scanner
|
gst-plugin-scanner
|
||||||
gst-completion-helper
|
gst-completion-helper
|
||||||
gst-ptp-helper
|
gst-ptp-helper
|
||||||
|
libgstreamer-gdb.py
|
||||||
*.o
|
*.o
|
||||||
|
|
|
@ -31,3 +31,10 @@ endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
EXTRA_DIST = ptp_helper_post_install.sh
|
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,
|
helpers_install_dir, with_ptp_helper_permissions,
|
||||||
setcap.found() ? setcap.path() : '')
|
setcap.found() ? setcap.path() : '')
|
||||||
endif
|
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