From: Michael Olbrich Date: Wed, 26 Sep 2018 11:33:31 +0000 (+0200) Subject: gst: add some gdb python macros X-Git-Tag: 1.16.2~200 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bc621cc3353c580cf3ce58f49e8f8508f663bd17;p=platform%2Fupstream%2Fgstreamer.git 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 --- diff --git a/configure.ac b/configure.ac index 93a6755..2bb7430 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/libs/gst/helpers/.gitignore b/libs/gst/helpers/.gitignore index 2a86569..87c36bf 100644 --- a/libs/gst/helpers/.gitignore +++ b/libs/gst/helpers/.gitignore @@ -1,4 +1,5 @@ gst-plugin-scanner gst-completion-helper gst-ptp-helper +libgstreamer-gdb.py *.o diff --git a/libs/gst/helpers/Makefile.am b/libs/gst/helpers/Makefile.am index d72a652..f76644a 100644 --- a/libs/gst/helpers/Makefile.am +++ b/libs/gst/helpers/Makefile.am @@ -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 diff --git a/libs/gst/helpers/glib_gobject_helper.py b/libs/gst/helpers/glib_gobject_helper.py new file mode 100644 index 0000000..5b08c38 --- /dev/null +++ b/libs/gst/helpers/glib_gobject_helper.py @@ -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 diff --git a/libs/gst/helpers/gst_gdb.py b/libs/gst/helpers/gst_gdb.py new file mode 100644 index 0000000..fc3b48e --- /dev/null +++ b/libs/gst/helpers/gst_gdb.py @@ -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) diff --git a/libs/gst/helpers/libgstreamer-gdb.py.in b/libs/gst/helpers/libgstreamer-gdb.py.in new file mode 100644 index 0000000..2cf6542 --- /dev/null +++ b/libs/gst/helpers/libgstreamer-gdb.py.in @@ -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 ()) diff --git a/libs/gst/helpers/meson.build b/libs/gst/helpers/meson.build index 891ea55..747cc9e 100644 --- a/libs/gst/helpers/meson.build +++ b/libs/gst/helpers/meson.build @@ -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)