This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

gdb pretty-printers for libstdc++


As part of Project Archer, we've added support for scriptable
pretty-printers to gdb.  We're going to be shipping this functionality
in F11, and we'll be integrating the final patches into gdb in time
for the 7.0 release.

More on Archer, if you are interested:

    http://sourceware.org/gdb/wiki/ProjectArcher

In order to test the new pretty-printing code, we've written printers
for most of the data structures in libstdc++.  Because these are tied
to the implementation details of the library, I think it is best to
maintain the printers in the library.  This patch implements that.

A given printer is written in Python.  Exactly how to write one, and
the gdb-specific APIs available to Python, are documented in the gdb
manual.

Printers can be auto-loaded by gdb when it reads an objfile.  gdb
looks for a file that is the objfile's real name with "-gdb.py" added;
e.g., libstdc++.so.6.0.11-gdb.py.  This patch attempts to set this up
properly, though the implementation is mildly hacky.

Here's an example of printing a std::map<int, std::string> to give you
an idea of how this appears to users:

    (gdb) p the_map 
    $1 = std::map with 2 elements = {
      [23] = "hello",
      [1024] = "world"
    }


The empty __init__.py files are to placate the Python module system.

The actual printers are in a versioned module to allow future changes
in gdb: when gdb supports multiple inferiors, it will be possible to
have inferiors using different versions of libstdc++; in this case, it
must be possible to load multiple printers without interference.


Let me know what you think.

Tom

2009-02-27  Tom Tromey  <tromey@redhat.com>

	* python/Makefile.in, , python/libstdcxx/__init__.py,
	python/libstdcxx/v6/__init__.py, python/libstdcxx/v6/printers.py,
	python/hook.in, python/Makefile.am: New files.
	* configure, Makefile.in: Rebuild.
	* acinclude.m4 (glibcxx_SUBDIRS): Add python.
	* Makefile.am (SUBDIRS): Add python.

Index: python/libstdcxx/__init__.py
===================================================================
--- python/libstdcxx/__init__.py	(revision 0)
+++ python/libstdcxx/__init__.py	(revision 0)
@@ -0,0 +1 @@
+
Index: python/libstdcxx/v6/__init__.py
===================================================================
--- python/libstdcxx/v6/__init__.py	(revision 0)
+++ python/libstdcxx/v6/__init__.py	(revision 0)
@@ -0,0 +1 @@
+
Index: python/libstdcxx/v6/printers.py
===================================================================
--- python/libstdcxx/v6/printers.py	(revision 0)
+++ python/libstdcxx/v6/printers.py	(revision 0)
@@ -0,0 +1,646 @@
+# Pretty-printers for libstc++.
+
+# Copyright (C) 2008, 2009 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import gdb
+import itertools
+import re
+
+class StdPointerPrinter:
+    "Print a smart pointer of some kind"
+
+    def __init__ (self, typename, val):
+        self.typename = typename
+        self.val = val
+
+    def to_string (self):
+        return '%s (count %d) %s' % (self.typename, self.val['_M_refcount'],
+                                     self.val['_M_ptr'])
+
+class UniquePointerPrinter:
+    "Print a unique_ptr"
+
+    def __init__ (self, val):
+        self.val = val
+
+    def to_string (self):
+        return self.val['_M_t']
+
+class StdListPrinter:
+    "Print a std::list"
+
+    class _iterator:
+        def __init__(self, nodetype, head):
+            self.nodetype = nodetype
+            self.base = head['_M_next']
+            self.head = head.address()
+            self.count = 0
+
+        def __iter__(self):
+            return self
+
+        def next(self):
+            if self.base == self.head:
+                raise StopIteration
+            elt = self.base.cast(self.nodetype).dereference()
+            self.base = elt['_M_next']
+            count = self.count
+            self.count = self.count + 1
+            return ('[%d]' % count, elt['_M_data'])
+
+    def __init__(self, val):
+        self.val = val
+
+    def children(self):
+        itype = self.val.type().template_argument(0)
+        nodetype = gdb.Type('std::_List_node<%s>' % itype).pointer()
+        return self._iterator(nodetype, self.val['_M_impl']['_M_node'])
+
+    def to_string(self):
+        if self.val['_M_impl']['_M_node'].address() == self.val['_M_impl']['_M_node']['_M_next']:
+            return 'empty std::list'
+        return 'std::list'
+
+class StdListIteratorPrinter:
+    "Print std::list::iterator"
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        itype = self.val.type().template_argument(0)
+        nodetype = gdb.Type('std::_List_node<%s>' % itype).pointer()
+        return self.val['_M_node'].cast(nodetype).dereference()['_M_data']
+
+class StdSlistPrinter:
+    "Print a __gnu_cxx::slist"
+
+    class _iterator:
+        def __init__(self, nodetype, head):
+            self.nodetype = nodetype
+            self.base = head['_M_head']['_M_next']
+            self.count = 0
+
+        def __iter__(self):
+            return self
+
+        def next(self):
+            if self.base == 0:
+                raise StopIteration
+            elt = self.base.cast(self.nodetype).dereference()
+            self.base = elt['_M_next']
+            count = self.count
+            self.count = self.count + 1
+            return ('[%d]' % count, elt['_M_data'])
+
+    def __init__(self, val):
+        self.val = val
+
+    def children(self):
+        itype = self.val.type().template_argument(0)
+        nodetype = gdb.Type('__gnu_cxx::_Slist_node<%s>' % itype).pointer()
+        return self._iterator(nodetype, self.val)
+
+    def to_string(self):
+        if self.val['_M_head']['_M_next'] == 0:
+            return 'empty __gnu_cxx::slist'
+        return '__gnu_cxx::slist'
+
+class StdSlistIteratorPrinter:
+    "Print __gnu_cxx::slist::iterator"
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        itype = self.val.type().template_argument(0)
+        nodetype = gdb.Type('__gnu_cxx::_Slist_node<%s>' % itype).pointer()
+        return self.val['_M_node'].cast(nodetype).dereference()['_M_data']
+
+class StdVectorPrinter:
+    "Print a std::vector"
+
+    class _iterator:
+        def __init__ (self, start, finish):
+            self.item = start
+            self.finish = finish
+            self.count = 0
+
+        def __iter__(self):
+            return self
+
+        def next(self):
+            if self.item == self.finish:
+                raise StopIteration
+            count = self.count
+            self.count = self.count + 1
+            elt = self.item.dereference()
+            self.item = self.item + 1
+            return ('[%d]' % count, elt)
+
+    def __init__(self, val):
+        self.val = val
+
+    def children(self):
+        return self._iterator(self.val['_M_impl']['_M_start'],
+                              self.val['_M_impl']['_M_finish'])
+
+    def to_string(self):
+        start = self.val['_M_impl']['_M_start']
+        finish = self.val['_M_impl']['_M_finish']
+        end = self.val['_M_impl']['_M_end_of_storage']
+        return ('std::vector of length %d, capacity %d'
+                % (int (finish - start), int (end - start)))
+
+    def display_hint(self):
+        return 'array'
+
+class StdVectorIteratorPrinter:
+    "Print std::vector::iterator"
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        return self.val['_M_current'].dereference()
+
+class StdStackOrQueuePrinter:
+    "Print a std::stack or std::queue"
+
+    def __init__ (self, typename, val):
+        self.typename = typename
+        self.visualizer = gdb.default_visualizer(val['c'])
+
+    def children (self):
+        return self.visualizer.children()
+
+    def to_string (self):
+        return '%s wrapping: %s' % (self.typename,
+                                    self.visualizer.to_string())
+
+    def display_hint (self):
+        if hasattr (self.visualizer, 'display_hint'):
+            return self.visualizer.display_hint ()
+        return None
+
+class RbtreeIterator:
+    def __init__(self, rbtree):
+        self.size = rbtree['_M_t']['_M_impl']['_M_node_count']
+        self.node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left']
+        self.count = 0
+
+    def __iter__(self):
+        return self
+
+    def __len__(self):
+        return int (self.size)
+
+    def next(self):
+        if self.count == self.size:
+            raise StopIteration
+        result = self.node
+        self.count = self.count + 1
+        if self.count < self.size:
+            # Compute the next node.
+            node = self.node
+            if node.dereference()['_M_right']:
+                node = node.dereference()['_M_right']
+                while node.dereference()['_M_left']:
+                    node = node.dereference()['_M_left']
+            else:
+                parent = node.dereference()['_M_parent']
+                while node == parent.dereference()['_M_right']:
+                    node = parent
+                    parent = parent.dereference()['_M_parent']
+                if node.dereference()['_M_right'] != parent:
+                    node = parent
+            self.node = node
+        return result
+
+# This is a pretty printer for std::_Rb_tree_iterator (which is
+# std::map::iterator), and has nothing to do with the RbtreeIterator
+# class above.
+class StdRbtreeIteratorPrinter:
+    "Print std::map::iterator"
+
+    def __init__ (self, val):
+        self.val = val
+
+    def to_string (self):
+        valuetype = self.val.type().template_argument(0)
+        nodetype = gdb.Type('std::_Rb_tree_node < %s >' % valuetype)
+        nodetype = nodetype.pointer()
+        return self.val.cast(nodetype).dereference()['_M_value_field']
+
+
+class StdMapPrinter:
+    "Print a std::map or std::multimap"
+
+    # Turn an RbtreeIterator into a pretty-print iterator.
+    class _iter:
+        def __init__(self, rbiter, type):
+            self.rbiter = rbiter
+            self.count = 0
+            self.type = type
+
+        def __iter__(self):
+            return self
+
+        def next(self):
+            if self.count % 2 == 0:
+                n = self.rbiter.next()
+                n = n.cast(self.type).dereference()['_M_value_field']
+                self.pair = n
+                item = n['first']
+            else:
+                item = self.pair['second']
+            result = ('[%d]' % self.count, item)
+            self.count = self.count + 1
+            return result
+
+    def __init__ (self, typename, val):
+        self.typename = typename
+        self.val = val
+        self.iter = RbtreeIterator (val)
+
+    def to_string (self):
+        return '%s with %d elements' % (self.typename, len (self.iter))
+
+    def children (self):
+        keytype = self.val.type().template_argument(0).const()
+        valuetype = self.val.type().template_argument(1)
+        nodetype = gdb.Type('std::_Rb_tree_node< std::pair< %s, %s > >' % (keytype, valuetype))
+        nodetype = nodetype.pointer()
+        return self._iter (self.iter, nodetype)
+
+    def display_hint (self):
+        return 'map'
+
+class StdSetPrinter:
+    "Print a std::set or std::multiset"
+
+    # Turn an RbtreeIterator into a pretty-print iterator.
+    class _iter:
+        def __init__(self, rbiter, type):
+            self.rbiter = rbiter
+            self.count = 0
+            self.type = type
+
+        def __iter__(self):
+            return self
+
+        def next(self):
+            item = self.rbiter.next()
+            item = item.cast(self.type).dereference()['_M_value_field']
+            # FIXME: this is weird ... what to do?
+            # Maybe a 'set' display hint?
+            result = ('[%d]' % self.count, item)
+            self.count = self.count + 1
+            return result
+
+    def __init__ (self, typename, val):
+        self.typename = typename
+        self.val = val
+        self.iter = RbtreeIterator (val)
+
+    def to_string (self):
+        return '%s with %d elements' % (self.typename, len (self.iter))
+
+    def children (self):
+        keytype = self.val.type().template_argument(0)
+        nodetype = gdb.Type('std::_Rb_tree_node< %s >' % keytype).pointer()
+        return self._iter (self.iter, nodetype)
+
+class StdBitsetPrinter:
+    "Print a std::bitset"
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string (self):
+        # If template_argument handled values, we could print the
+        # size.  Or we could use a regexp on the type.
+        return 'std::bitset'
+
+    def children (self):
+        words = self.val['_M_w']
+        wtype = words.type()
+
+        # The _M_w member can be either an unsigned long, or an
+        # array.  This depends on the template specialization used.
+        # If it is a single long, convert to a single element list.
+        if wtype.code () == gdb.TYPE_CODE_ARRAY:
+            tsize = wtype.target ().sizeof ()
+        else:
+            words = [words]
+            tsize = wtype.sizeof () 
+
+        nwords = wtype.sizeof() / tsize
+        result = []
+        byte = 0
+        while byte < nwords:
+            w = words[byte]
+            bit = 0
+            while w != 0:
+                if (w & 1) != 0:
+                    # Another spot where we could use 'set'?
+                    result.append(('[%d]' % (byte * tsize * 8 + bit), 1))
+                bit = bit + 1
+                w = w >> 1
+            byte = byte + 1
+        return result
+
+class StdDequePrinter:
+    "Print a std::deque"
+
+    class _iter:
+        def __init__(self, node, start, end, last, buffer_size):
+            self.node = node
+            self.p = start
+            self.end = end
+            self.last = last
+            self.buffer_size = buffer_size
+            self.count = 0
+
+        def __iter__(self):
+            return self
+
+        def next(self):
+            if self.p == self.last:
+                raise StopIteration
+
+            result = ('[%d]' % self.count, self.p.dereference())
+            self.count = self.count + 1
+
+            # Advance the 'cur' pointer.
+            self.p = self.p + 1
+            if self.p == self.end:
+                # If we got to the end of this bucket, move to the
+                # next bucket.
+                self.node = self.node + 1
+                self.p = self.node[0]
+                self.end = self.p + self.buffer_size
+
+            return result
+
+    def __init__(self, val):
+        self.val = val
+        self.elttype = val.type().template_argument(0)
+        size = self.elttype.sizeof ()
+        if size < 512:
+            self.buffer_size = int (512 / size)
+        else:
+            self.buffer_size = 1
+
+    def to_string(self):
+        start = self.val['_M_impl']['_M_start']
+        end = self.val['_M_impl']['_M_finish']
+
+        delta_n = end['_M_node'] - start['_M_node'] - 1
+        delta_s = start['_M_last'] - start['_M_cur']
+        delta_e = end['_M_cur'] - end['_M_first']
+
+        size = self.buffer_size * delta_n + delta_s + delta_e
+
+        return 'std::deque with %d elements' % long (size)
+
+    def children(self):
+        start = self.val['_M_impl']['_M_start']
+        end = self.val['_M_impl']['_M_finish']
+        return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'],
+                          end['_M_cur'], self.buffer_size)
+
+    def display_hint (self):
+        return 'array'
+
+class StdDequeIteratorPrinter:
+    "Print std::deque::iterator"
+
+    def __init__(self, val):
+        self.val = val
+
+    def to_string(self):
+        return self.val['_M_cur'].dereference()
+
+class WideEncoding (gdb.Parameter):
+    """The target wide character set is the encoding used for wchar_t."""
+
+    set_doc = "Set the target wide character set."
+    show_doc = "Show the target wide character set."
+
+    # FIXME: needs a complete method -- but does Parameter support it?
+    def __init__ (self):
+        super (WideEncoding, self).__init__ ("target-wide-charset",
+                                             gdb.COMMAND_SUPPORT,
+                                             gdb.PARAM_STRING)
+        # I think this is ok for most glibc locales.
+        self.value = 'UTF-32'
+
+target_wide_charset = WideEncoding()
+
+class StdStringPrinter:
+    "Print a std::basic_string of some kind"
+
+    def __init__(self, encoding, val):
+        self.encoding = encoding
+        self.val = val
+
+    def to_string(self):
+        # Look up the target encoding as late as possible.
+        encoding = self.encoding
+        if encoding is None:
+            encoding = gdb.parameter('target-charset')
+        elif isinstance(encoding, WideEncoding):
+            encoding = encoding.value
+        return self.val['_M_dataplus']['_M_p'].string(encoding)
+
+    def display_hint (self):
+        return 'string'
+
+class Tr1HashtableIterator:
+    def __init__ (self, hash):
+        self.count = 0
+        self.n_buckets = hash['_M_element_count']
+        if self.n_buckets == 0:
+            self.node = False
+        else:
+            self.bucket = hash['_M_buckets']
+            self.node = self.bucket[0]
+            self.update ()
+
+    def __iter__ (self):
+        return self
+
+    def update (self):
+        # If we advanced off the end of the chain, move to the next
+        # bucket.
+        while self.node == 0:
+            self.bucket = self.bucket + 1
+            self.node = self.bucket[0]
+
+       # If we advanced off the end of the bucket array, then
+       # we're done.
+        if self.count == self.n_buckets:
+            self.node = False
+        else:
+            self.count = self.count + 1
+
+    def next (self):
+        if not self.node:
+            raise StopIteration
+        result = self.node.dereference()['_M_v']
+        self.node = self.node.dereference()['_M_next']
+        self.update ()
+        return result
+
+class Tr1UnorderedSetPrinter:
+    "Print a tr1::unordered_set"
+
+    def __init__ (self, typename, val):
+        self.typename = typename
+        self.val = val
+
+    def to_string (self):
+        return '%s with %d elements' % (self.typename, self.val['_M_element_count'])
+
+    @staticmethod
+    def format_count (i):
+        return '[%d]' % i
+
+    def children (self):
+        counter = itertools.imap (self.format_count, itertools.count())
+        return itertools.izip (counter, Tr1HashtableIterator (self.val))
+
+class Tr1UnorderedMapPrinter:
+    "Print a tr1::unordered_map"
+
+    def __init__ (self, typename, val):
+        self.typename = typename
+        self.val = val
+
+    def to_string (self):
+        return '%s with %d elements' % (self.typename, self.val['_M_element_count'])
+
+    @staticmethod
+    def flatten (list):
+        for elt in list:
+            for i in elt:
+                yield i
+
+    @staticmethod
+    def format_one (elt):
+        return (elt['first'], elt['second'])
+
+    @staticmethod
+    def format_count (i):
+        return '[%d]' % i
+
+    def children (self):
+        counter = itertools.imap (self.format_count, itertools.count())
+        # Map over the hash table and flatten the result.
+        data = self.flatten (itertools.imap (self.format_one, Tr1HashtableIterator (self.val)))
+        # Zip the two iterators together.
+        return itertools.izip (counter, data)
+
+    def display_hint (self):
+        return 'map'
+
+def register_libstdcxx_printers (obj):
+    "Register libstdc++ pretty-printers with objfile Obj."
+
+    if obj == None:
+        obj = gdb
+
+    obj.pretty_printers.append (lookup_function)
+
+def lookup_function (val):
+    "Look-up and return a pretty-printer that can print val."
+
+    # Get the type.
+    type = val.type ();
+
+    # If it points to a reference, get the reference.
+    if type.code () == gdb.TYPE_CODE_REF:
+        type = type.target ()
+
+    # Get the unqualified type, stripped of typedefs.
+    type = type.unqualified ().strip_typedefs ()
+
+    # Get the type name.    
+    typename = type.tag ()
+    if typename == None:
+        return None
+
+    # Iterate over local dictionary of types to determine
+    # if a printer is registered for that type.  Return an
+    # instantiation of the printer if found.
+    for function in pretty_printers_dict:
+        if function.search (typename):
+            return pretty_printers_dict[function] (val)
+        
+    # Cannot find a pretty printer.  Return None.
+    return None
+
+def build_libstdcxx_dictionary ():
+    # libstdc++ objects requiring pretty-printing.
+    # In order from:
+    # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html
+    pretty_printers_dict[re.compile('^std::basic_string<char,.*>$')] = lambda val: StdStringPrinter(None, val)
+    pretty_printers_dict[re.compile('^std::basic_string<wchar_t,.*>$')] = lambda val: StdStringPrinter(target_wide_charset, val)
+    pretty_printers_dict[re.compile('^std::basic_string<char16_t,.*>$')] = lambda val: StdStringPrinter('UTF-16', val)
+    pretty_printers_dict[re.compile('^std::basic_string<char32_t,.*>$')] = lambda val: StdStringPrinter('UTF-32', val)
+    pretty_printers_dict[re.compile('^std::bitset<.*>$')] = StdBitsetPrinter
+    pretty_printers_dict[re.compile('^std::deque<.*>$')] = StdDequePrinter
+    pretty_printers_dict[re.compile('^std::list<.*>$')] = StdListPrinter
+    pretty_printers_dict[re.compile('^std::map<.*>$')] = lambda val: StdMapPrinter("std::map", val)
+    pretty_printers_dict[re.compile('^std::multimap<.*>$')] = lambda val: StdMapPrinter("std::multimap", val)
+    pretty_printers_dict[re.compile('^std::multiset<.*>$')] = lambda val: StdSetPrinter("std::multiset", val)
+    pretty_printers_dict[re.compile('^std::priority_queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::priority_queue", val)
+    pretty_printers_dict[re.compile('^std::queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::queue", val)
+    pretty_printers_dict[re.compile('^std::set<.*>$')] = lambda val: StdSetPrinter("std::set", val)
+    pretty_printers_dict[re.compile('^std::stack<.*>$')] = lambda val: StdStackOrQueuePrinter("std::stack", val)
+    pretty_printers_dict[re.compile('^std::vector<.*>$')] = StdVectorPrinter
+    # vector<bool>
+
+    # C++0x stuff.
+    # array - the default seems reasonable
+    # smart_ptr?  seems to only be in boost right now
+    pretty_printers_dict[re.compile('^std::tr1::shared_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::shared_ptr', val)
+    pretty_printers_dict[re.compile('^std::tr1::weak_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::weak_ptr', val)
+    pretty_printers_dict[re.compile('^std::tr1::unique_ptr<.*>$')] = UniquePointerPrinter
+    pretty_printers_dict[re.compile('^std::tr1::unordered_map<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_map', val)
+    pretty_printers_dict[re.compile('^std::tr1::unordered_set<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_set', val)
+    pretty_printers_dict[re.compile('^std::tr1::unordered_multimap<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_multimap', val)
+    pretty_printers_dict[re.compile('^std::tr1::unordered_multiset<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_multiset', val)
+
+    # Extensions.
+    pretty_printers_dict[re.compile('^__gnu_cxx::slist<.*>$')] = StdSlistPrinter
+
+    if True:
+        # These shouldn't be necessary, if GDB "print *i" worked.
+        # But it often doesn't, so here they are.
+        pretty_printers_dict[re.compile('^std::_List_iterator<.*>$')] = lambda val: StdListIteratorPrinter(val)
+        pretty_printers_dict[re.compile('^std::_List_const_iterator<.*>$')] = lambda val: StdListIteratorPrinter(val)
+        pretty_printers_dict[re.compile('^std::_Rb_tree_iterator<.*>$')] = lambda val: StdRbtreeIteratorPrinter(val)
+        pretty_printers_dict[re.compile('^std::_Rb_tree_const_iterator<.*>$')] = lambda val: StdRbtreeIteratorPrinter(val)
+        pretty_printers_dict[re.compile('^std::_Deque_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val)
+        pretty_printers_dict[re.compile('^std::_Deque_const_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val)
+        pretty_printers_dict[re.compile('^__gnu_cxx::__normal_iterator<.*>$')] = lambda val: StdVectorIteratorPrinter(val)
+        pretty_printers_dict[re.compile('^__gnu_cxx::_Slist_iterator<.*>$')] = lambda val: StdSlistIteratorPrinter(val)
+
+pretty_printers_dict = {}
+
+build_libstdcxx_dictionary ()
Index: python/hook.in
===================================================================
--- python/hook.in	(revision 0)
+++ python/hook.in	(revision 0)
@@ -0,0 +1,27 @@
+# -*- python -*-
+# Copyright (C) 2009 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import sys
+import gdb
+
+# Update module path.
+dir = '@dir@'
+if not dir in sys.path:
+    sys.path.insert(0, dir)
+
+# Load the pretty-printers.
+from libstdcxx.v6.printers import register_libstdcxx_printers
+register_libstdcxx_printers (gdb.current_objfile ())
Index: python/Makefile.am
===================================================================
--- python/Makefile.am	(revision 0)
+++ python/Makefile.am	(revision 0)
@@ -0,0 +1,43 @@
+## Makefile for the python subdirectory of the GNU C++ Standard library.
+##
+## Copyright (C) 2009 Free Software Foundation, Inc.
+##
+## This file is part of the libstdc++ version 3 distribution.
+## Process this file with automake to produce Makefile.in.
+
+## This file is part of the GNU ISO C++ Library.  This library is free
+## software; you can redistribute it and/or modify it under the
+## terms of the GNU General Public License as published by the
+## Free Software Foundation; either version 2, or (at your option)
+## any later version.
+
+## This library is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+
+## You should have received a copy of the GNU General Public License along
+## with this library; see the file COPYING.  If not, write to the Free
+## Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+## USA.
+
+include $(top_srcdir)/fragment.am
+
+## Where to install the module code.
+pythondir = $(pkgdatadir)/python
+
+all-local: gdb.py
+
+nobase_python_DATA = \
+    libstdcxx/v6/printers.py \
+    libstdcxx/v6/__init__.py \
+    libstdcxx/__init__.py
+
+gdb.py: hook.in Makefile
+	sed -e 's,@dir@,$(pythondir),' < $(srcdir)/hook.in > $@
+
+install-data-local: gdb.py
+	@$(mkdir_p) $(DESTDIR)$(toolexeclibdir)
+	@libname=`cd $(toolexeclibdir) && ls -r libstdc++* | fgrep -v gdb.py | sed 1q`; \
+	echo " $(INSTALL_DATA) gdb.py $(DESTDIR)$(toolexeclibdir)/$$libname-gdb.py"; \
+	$(INSTALL_DATA) gdb.py $(DESTDIR)$(toolexeclibdir)/$$libname-gdb.py
Index: acinclude.m4
===================================================================
--- acinclude.m4	(revision 144466)
+++ acinclude.m4	(working copy)
@@ -49,7 +49,7 @@
   # Keep these sync'd with the list in Makefile.am.  The first provides an
   # expandable list at autoconf time; the second provides an expandable list
   # (i.e., shell variable) at configure time.
-  m4_define([glibcxx_SUBDIRS],[include libsupc++ src doc po testsuite])
+  m4_define([glibcxx_SUBDIRS],[include libsupc++ python src doc po testsuite])
   SUBDIRS='glibcxx_SUBDIRS'
 
   # These need to be absolute paths, yet at the same time need to
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 144466)
+++ Makefile.am	(working copy)
@@ -28,7 +28,8 @@
   hosted_source = doc src po testsuite
 endif
 ## Keep this list sync'd with acinclude.m4:GLIBCXX_CONFIGURE.
-SUBDIRS = include libsupc++ $(hosted_source)
+## Note that python must come after src.
+SUBDIRS = include libsupc++ $(hosted_source) python
 
 ACLOCAL_AMFLAGS = -I . -I .. -I ../config
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]