]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Added a small set of pretty printers for GDB. 1578/head
authorDavid Wells <wellsd2@rpi.edu>
Thu, 10 Sep 2015 18:29:12 +0000 (14:29 -0400)
committerDavid Wells <wellsd2@rpi.edu>
Fri, 11 Sep 2015 14:44:26 +0000 (10:44 -0400)
contrib/utilities/dotgdbinit.py [new file with mode: 0644]
doc/news/changes.h

diff --git a/contrib/utilities/dotgdbinit.py b/contrib/utilities/dotgdbinit.py
new file mode 100644 (file)
index 0000000..56786a7
--- /dev/null
@@ -0,0 +1,206 @@
+# ---------------------------------------------------------------------
+#
+# Copyright (C) 2015 by the deal.II authors
+#
+# This file is part of the deal.II library.
+#
+# The deal.II library is free software; you can use it, redistribute
+# it, and/or modify it under the terms of the GNU Lesser General
+# Public License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+# The full text of the license can be found in the file LICENSE at
+# the top level of the deal.II distribution.
+#
+# ---------------------------------------------------------------------
+
+#
+# Instructions: Place a copy of this file, renamed as ".gdbinit", in your home
+# directory to enable pretty-printing of various deal.II objects.
+#
+# This has only been tested with GDB 7.7.1 and newer, but it should work with
+# slightly older versions of GDB (the Python interface was added in 7.0,
+# released in 2009).
+#
+# Authors: Wolfgang Bangerth, 2015, David Wells, 2015
+#
+set print pretty 1
+
+python
+
+import gdb
+import re
+
+
+def build_output_string(keys, accessor):
+    """Build an output string of the form
+    {
+      a = foo,
+      b = bar
+    }
+    where a and b are elements of keys and foo and bar are values of
+    accessor (e.g., accessor['a'] = foo).
+
+    Note that accessor need not be a dictionary (i.e., gdb.Values
+    redefines __getitem__)."""
+    return ("{\n" +
+            ",\n".join(["  {} = {}".format(key, accessor[key])
+                        for key in keys]) +
+            "\n}")
+
+
+class PointPrinter(object):
+    """Print a deal.II Point instance."""
+    def __init__(self, typename, val):
+        self.typename = typename
+        self.val = val
+
+    def to_string(self):
+        return self.val['values']
+
+
+class TensorPrinter(object):
+    """Print a deal.II Tensor instance."""
+    def __init__(self, typename, val):
+        self.typename = typename
+        self.val = val
+
+    def to_string(self):
+        if int(self.val.type.template_argument(0)) == 0:
+            return self.val['value']
+        else:
+            return self.val['values']
+
+
+class TriaIteratorPrinter(object):
+    """Print a deal.II TriaIterator instance."""
+    def __init__(self, typename, val):
+        self.typename = typename
+        self.val = val
+
+    def to_string(self):
+        keys = ['tria', 'present_level', 'present_index']
+        if 'DoFHandler' in str(self.val.type.template_argument(0)):
+            keys.insert(1, 'dof_handler')
+
+        return build_output_string(keys, self.val['accessor'])
+
+
+class VectorPrinter(object):
+    """Print a deal.II Vector instance."""
+    def __init__(self, typename, val):
+        self.typename = typename
+        self.val = val
+
+    def children(self):
+        # The first entry (see the "Pretty Printing API" documentation of GDB)
+        # in the tuple should be a name for the child, which should be nothing
+        # (an empty string) here.
+        return (("", (self.val['val'] + count).dereference())
+                for count in range(int(self.val['vec_size'])))
+
+    def to_string(self):
+        return "{}[{}]".format(self.val.type.template_argument(0),
+                               self.val['vec_size'])
+
+    @staticmethod
+    def display_hint():
+        """Provide a hint to GDB that this is an array-like container
+        (so print values in sequence)."""
+        return "array"
+
+
+class QuadraturePrinter(object):
+    """Print a deal.II Quadrature instance."""
+    def __init__(self, typename, val):
+        self.typename = typename
+        self.val = val
+
+    def to_string(self):
+        return build_output_string(['quadrature_points', 'weights'], self.val)
+
+
+class RxPrinter(object):
+    """A "regular expression" printer which conforms to the
+    "SubPrettyPrinter" protocol from gdb.printing."""
+    def __init__(self, name, function):
+        self.name = name
+        self.function = function
+        self.enabled = True
+
+    def __call__(self, value):
+        if self.enabled:
+            return self.function(self.name, value)
+        else:
+            return None
+
+
+class Printer(object):
+    """A pretty-printer that conforms to the "PrettyPrinter" protocol
+    from gdb.printing. It can also be used directly as an old-style
+    printer."""
+    def __init__(self, name):
+        self.name = name
+        self.subprinters = list()
+        self.lookup = dict()
+        self.enabled = True
+        self.compiled_rx = re.compile('^([a-zA-Z0-9_:]+)<.*>$')
+
+    def add(self, name, function):
+        printer = RxPrinter(name, function)
+        self.subprinters.append(printer)
+        self.lookup[name] = printer
+
+    @staticmethod
+    def get_basic_type(object_type):
+        # If it points to a reference, then get the reference.
+        if object_type.code == gdb.TYPE_CODE_REF:
+            object_type = object_type.target()
+
+        object_type = object_type.unqualified().strip_typedefs()
+
+        return object_type.tag
+
+    def __call__(self, val):
+        typename = self.get_basic_type(val.type)
+        if typename:
+            # All the types we match are template types, so we can use a
+            # dictionary.
+            match = self.compiled_rx.match(typename)
+            if match:
+                basename = match.group(1)
+                if basename in self.lookup:
+                    return self.lookup[basename](val)
+
+        return None
+
+
+dealii_printer = Printer("deal.II")
+
+
+def register_dealii_printers():
+    """Register deal.II pretty-printers with gdb."""
+    printers = {
+        PointPrinter: ['Point'],
+        TensorPrinter: ['Tensor'],
+        VectorPrinter: ['Vector'],
+        TriaIteratorPrinter:
+        ['TriaRawIterator', 'TriaIterator', 'TriaActiveIterator'],
+        QuadraturePrinter:
+        ['Quadrature', 'QGauss', 'QGaussLobatto', 'QMidpoint', 'QSimpson',
+         'QTrapez', 'QMilne', 'QWeddle', 'QGaussLog', 'QGaussLogR',
+         'QGaussOneOverR', 'QSorted', 'QTelles', 'QGaussChebyshev',
+         'QGaussRadauChebyshev', 'QIterated', 'QAnisotropic']
+    }
+    for printer, class_names in printers.items():
+        for class_name in class_names:
+            dealii_printer.add('dealii::' + class_name, printer)
+    try:
+        from gdb import printing
+        printing.register_pretty_printer(gdb, dealii_printer)
+    except ImportError:
+        gdb.pretty_printers.append(dealii_printer)
+
+
+register_dealii_printers()
+
+end
index 64c86b4ec821e7815a2330c4cb7c506d11d94863..a153bdb7d0befbd747e530951f937bbfe29589fc 100644 (file)
@@ -122,6 +122,13 @@ inconvenience this causes.
 
 
 <ol>
+  <li> New: A python script (including instructions) for enabling pretty
+  printing with GDB is now available in
+  <tt>/contrib/utilities/dotgdbinit.py</tt>.
+  <br>
+  (Wolfgang Bangerth, David Wells, 2015/09/11)
+  </li>
+
   <li> Improved: When available, deal.II now uses the "gold" linker, a
   reimplementation of the traditional Unix "ld" linker that is substantially
   faster. This reduces build and, in particular, test turnaround times.

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.