>From 2927820959e1ffdb83c8f196a9195673bc927e44 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Fri, 13 Nov 2015 16:44:45 +0100 Subject: [PATCH] CONTRIB: Add a gdb pretty-printer for ldb and sysdb_attrs Printing ldb structures and sysdb_attrs can be a pain. This patch adds a gdb pretty-printer to help SSSD and LDB debugging plugins Activate them by putting: source /path/to/this/file.py to your .gdbinit file To bypass the pretty printer and print the raw values, use the "/r" option: print /r foobar --- contrib/gdb/sssd_gdb_plugin.py | 196 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 contrib/gdb/sssd_gdb_plugin.py diff --git a/contrib/gdb/sssd_gdb_plugin.py b/contrib/gdb/sssd_gdb_plugin.py new file mode 100644 index 0000000000000000000000000000000000000000..730c7e894297012d897aafff97a3d8f8a3b7d042 --- /dev/null +++ b/contrib/gdb/sssd_gdb_plugin.py @@ -0,0 +1,196 @@ +# SSSD and LDB debugging plugins +# +# Activate them by putting: +# source /path/to/this/file.py +# to your .gdbinit file +# +# To bypass the pretty printer and print the raw values, use the "/r" option: +# print /r foobar +import gdb + + +def gdb_printer_decorator(fn): + gdb.pretty_printers.append(fn) + return fn + + +def indent_string(s, indent): + return '\n'.join(["%s%s" % ("\t" * indent, part) for part in s.split('\n')]) + + +class StringPrinter(object): + "Shared code between different string-printing classes" + def __init__(self, val): + self.val = val + + def to_string(self): + return self.as_string() + + +class LdbDnPrinter(StringPrinter): + " print an ldb dn " + + def as_string(self, indent=0): + ret = "{ <%s>\tlinearized:%s }" % (self.val.type, self.val['linearized']) + return indent_string(ret, indent) + + +class LdbValPrinter(StringPrinter): + " print a ldb value" + + def as_string(self, indent=0): + ret = "data = %(data)s, length = %(length)s" % self.val + return indent_string("{ <%s>\t%s }" % (self.val.type, ret), indent) + + +class LdbMessageElementPrinter(StringPrinter): + " print a ldb message element " + + def as_string(self, indent=0): + ret = "flags = %(flags)s, name = %(name)s, num_values = %(num_values)s" % self.val + try: + nvals = int(self.val['num_values']) + except ValueError: + return "num_values is not numeric?" + + for i in range(nvals): + ldbval = LdbValPrinter(self.val['values'][i]) + ret += "\n%s" % (ldbval.as_string(indent+1)) + + return indent_string("{ <%s>\t%s }" % (self.val.type, ret), indent) + + +class LdbMessagePrinter(StringPrinter): + " print a ldb message " + + def as_string(self, indent=0): + try: + nels = int(self.val['num_elements']) + except ValueError: + return "num_elements is not numeric?" + + dn = LdbDnPrinter(self.val['dn']) + ret = "num_elements:\t%s\ndn:\t%s\nelements:\t" % (nels, dn.as_string(indent)) + + for i in range(nels): + el = LdbMessageElementPrinter(self.val['elements'][i]) + ret += "\n%s" % (el.as_string(indent+1)) + + return indent_string("{ <%s>\n%s }" % (self.val.type, ret), indent) + + +class LdbResultPrinter(StringPrinter): + " print a ldb message element " + + def as_string(self, indent=0): + ret = "count = %(count)s, extended = %(extended)s, controls = %(controls)s, refs = %(refs)s" % self.val + try: + count = int(self.val['count']) + except ValueError: + ret += 'Count is not numeric value?' + return ret + + for i in range(count): + msg = LdbMessagePrinter(self.val['msgs'][i]) + ret += "\n%s" % (msg.as_string(indent+1)) + + return indent_string("{ <%s>\t%s }" % (self.val.type, ret), indent) + + +class SysdbAttrsPrinter(StringPrinter): + " print a struct sysdb attrs " + + def as_string(self, indent=0): + ret = "num = %(num)s" % self.val + + try: + num = int(self.val['num']) + except ValueError: + ret += 'num is not numeric value?' + return ret + + for i in range(num): + el = LdbMessageElementPrinter(self.val['a'][i]) + ret += "\n%s" % (el.as_string(indent+1)) + + return indent_string("{ <%s>\t%s }" % (self.val.type, ret), indent) + + +# --- +# --- register pretty printers --- +# --- +@gdb_printer_decorator +def ldb_val_element_printer(val): + if str(val.type) == 'struct ldb_dn': + return LdbDnPrinter(val) + return None + + +@gdb_printer_decorator +def ldb_val_element_printer(val): + if str(val.type) == 'struct ldb_val': + return LdbValPrinter(val) + return None + + +@gdb_printer_decorator +def ldb_message_element_printer(val): + if str(val.type) == 'struct ldb_message_element': + return LdbMessageElementPrinter(val) + return None + + +@gdb_printer_decorator +def ldb_message_printer(val): + if str(val.type) == 'struct ldb_message': + return LdbMessagePrinter(val) + return None + + +@gdb_printer_decorator +def ldb_result_printer(val): + if str(val.type) == 'struct ldb_result': + return LdbResultPrinter(val) + return None + + +@gdb_printer_decorator +def sysdb_attrs_printer(val): + if str(val.type) == 'struct sysdb_attrs': + return SysdbAttrsPrinter(val) + return None + + +# --- +# --- set a breakpoint at the tevent_req finish fn --- +# --- +class TeventBreak(gdb.Command): + """Break at the tevent finish location """ + + def __init__(self): + super(TeventBreak, self).__init__("tbr", gdb.COMMAND_BREAKPOINTS) + + def invoke(self, arg, from_tty): + req = gdb.parse_and_eval(arg) + if not hasattr(req, 'type'): + print('cannot determine the type of the variable') + return + if str(req.type) != 'struct tevent_req *': + print('wrong attribute - must be a tevent_req pointer') + return + + try: + fn = req['async']['fn'] + except KeyError: + print("No async function defined?") + return + + try: + fnaddr = str(fn).split()[0].strip() + except IndexError: + print("Cannot get function address") + return + + b = gdb.Breakpoint("*%s" % fnaddr) + +TeventBreak() -- 2.4.3