From patchwork Wed Jan 26 21:39:50 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Tromey X-Patchwork-Id: 80554 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 46E59B70E9 for ; Thu, 27 Jan 2011 08:40:24 +1100 (EST) Received: (qmail 7277 invoked by alias); 26 Jan 2011 21:40:14 -0000 Received: (qmail 6785 invoked by uid 22791); 26 Jan 2011 21:40:04 -0000 X-SWARE-Spam-Status: No, hits=-6.7 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_BJ, TW_CX, TW_DC, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 26 Jan 2011 21:39:54 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id p0QLdqf4007983 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Wed, 26 Jan 2011 16:39:52 -0500 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p0QLdpot010164; Wed, 26 Jan 2011 16:39:52 -0500 Received: from opsy.redhat.com (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id p0QLdok3003769; Wed, 26 Jan 2011 16:39:51 -0500 Received: by opsy.redhat.com (Postfix, from userid 500) id 9C5F43783AD; Wed, 26 Jan 2011 14:39:50 -0700 (MST) From: Tom Tromey To: libstdc Subject: FYI: update libstdc++ pretty-printers CC: gcc-patches@gcc.gnu.org Date: Wed, 26 Jan 2011 14:39:50 -0700 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux) MIME-Version: 1.0 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Barring objections, I will check this in during the next stage 1. Doug Evans recently added some features to gdb to make it possible for the user to individually enable or disable pretty-printers. In order for this to work, the printers must conform to a certain extended protocol. This patch updates the libstdc++ printers to work this way. The change is done in a backward-compatible way, so that they will continue to work properly in older versions of gdb. This patch also simplifies the printers somewhat, and probably speeds up printer recognition as well, though I did not try to measure that. Tom 2011-01-26 Tom Tromey * python/libstdcxx/v6/printers.py (_use_gdb_pp): New global. Try to import `gdb.printing' module. (UniquePointerPrinter.__init__): Add 'typename' argument. (StdSlistPrinter.__init__): Likewise. (StdSlistIteratorPrinter.__init__): Likewise. (StdVectorIteratorPrinter.__init__): Likewise. (StdRbtreeIteratorPrinter.__init__): Likewise. (StdDebugIteratorPrinter.__init__): Likewise. (StdDequeIteratorPrinter.__init__): Likewise. (StdStringPrinter.__init__): Likewise. (RxPrinter, Printer): New class. (libstdcxx_printer): New global. (register_libstdcxx_printers): Rewrite. (build_libstdcxx_dictionary): Rewrite. (pretty_printers_dict): Remove. Index: python/libstdcxx/v6/printers.py =================================================================== --- python/libstdcxx/v6/printers.py (revision 168933) +++ python/libstdcxx/v6/printers.py (working copy) @@ -1,6 +1,6 @@ # Pretty-printers for libstc++. -# Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc. +# Copyright (C) 2008, 2009, 2010, 2011 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 @@ -19,6 +19,13 @@ import itertools import re +# Try to use the new-style pretty-printing if available. +_use_gdb_pp = True +try: + import gdb.printing +except ImportError: + _use_gdb_pp = False + class StdPointerPrinter: "Print a smart pointer of some kind" @@ -36,7 +43,7 @@ class UniquePointerPrinter: "Print a unique_ptr" - def __init__ (self, val): + def __init__ (self, typename, val): self.val = val def to_string (self): @@ -125,7 +132,7 @@ self.count = self.count + 1 return ('[%d]' % count, elt['_M_data']) - def __init__(self, val): + def __init__(self, typename, val): self.val = val def children(self): @@ -141,7 +148,7 @@ class StdSlistIteratorPrinter: "Print __gnu_cxx::slist::iterator" - def __init__(self, val): + def __init__(self, typename, val): self.val = val def to_string(self): @@ -228,7 +235,7 @@ class StdVectorIteratorPrinter: "Print std::vector::iterator" - def __init__(self, val): + def __init__(self, typename, val): self.val = val def to_string(self): @@ -351,7 +358,7 @@ class StdRbtreeIteratorPrinter: "Print std::map::iterator" - def __init__ (self, val): + def __init__ (self, typename, val): self.val = val def to_string (self): @@ -363,7 +370,7 @@ class StdDebugIteratorPrinter: "Print a debug enabled version of an iterator" - def __init__ (self, val): + def __init__ (self, typename, val): self.val = val # Just strip away the encapsulating __gnu_debug::_Safe_iterator @@ -557,7 +564,7 @@ class StdDequeIteratorPrinter: "Print std::deque::iterator" - def __init__(self, val): + def __init__(self, typename, val): self.val = val def to_string(self): @@ -566,7 +573,7 @@ class StdStringPrinter: "Print a std::basic_string of some kind" - def __init__(self, val): + def __init__(self, typename, val): self.val = val def to_string(self): @@ -678,125 +685,186 @@ def display_hint (self): return 'map' -def register_libstdcxx_printers (obj): - "Register libstdc++ pretty-printers with objfile Obj." +# A "regular expression" printer which conforms to the +# "SubPrettyPrinter" protocol from gdb.printing. +class RxPrinter(object): + def __init__(self, name, function): + super(RxPrinter, self).__init__() + self.name = name + self.function = function + self.enabled = True - if obj == None: - obj = gdb + def invoke(self, value): + return self.function(self.name, value) - obj.pretty_printers.append (lookup_function) +# A pretty-printer that conforms to the "PrettyPrinter" protocol from +# gdb.printing. It can also be used directly as an old-style printer. +class Printer(object): + def __init__(self, name): + super(Printer, self).__init__() + self.name = name + self.subprinters = [] + self.lookup = {} + self.enabled = True + self.compiled_rx = re.compile('^([a-zA-Z0-9_:]+)<.*>$') -def lookup_function (val): - "Look-up and return a pretty-printer that can print val." + def add(self, name, function): + # A small sanity check. + # FIXME + if not self.compiled_rx.match(name + '<>'): + raise ValueError, 'libstdc++ programming error: "%s" does not match' % name + printer = RxPrinter(name, function) + self.subprinters.append(printer) + self.lookup[name] = printer - # Get the type. - type = val.type + @staticmethod + def get_basic_type(type): + # If it points to a reference, get the reference. + if type.code == gdb.TYPE_CODE_REF: + type = type.target () - # 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 unqualified type, stripped of typedefs. - type = type.unqualified ().strip_typedefs () + return type.tag - # Get the type name. - typename = type.tag - if typename == None: + def __call__(self, val): + typename = self.get_basic_type(val.type) + if not typename: + return None + + # All the types we match are template types, so we can use a + # dictionary. + match = self.compiled_rx.match(typename) + if not match: + return None + + if match.group(1) in self.lookup: + return self.lookup[match.group(1)].invoke(val) + + # Cannot find a pretty printer. Return 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 +libstdcxx_printer = None +def register_libstdcxx_printers (obj): + "Register libstdc++ pretty-printers with objfile Obj." + + global _use_gdb_pp + global libstdcxx_printer + + if _use_gdb_pp: + gdb.printing.register_pretty_printer(obj, libstdcxx_printer) + else: + if obj is None: + obj = gdb + obj.pretty_printers.append(libstdcxx_printer) + def build_libstdcxx_dictionary (): + global libstdcxx_printer + + libstdcxx_printer = Printer("libstdc++-v6") + # 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<.*>$')] = lambda val: StdStringPrinter(val) - pretty_printers_dict[re.compile('^std::bitset<.*>$')] = lambda val: StdBitsetPrinter("std::bitset", val) - pretty_printers_dict[re.compile('^std::deque<.*>$')] = lambda val: StdDequePrinter("std::deque", val) - pretty_printers_dict[re.compile('^std::list<.*>$')] = lambda val: StdListPrinter("std::list", val) - 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::tuple<.*>$')] = lambda val: StdTuplePrinter("std::tuple", 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::unique_ptr<.*>$')] = UniquePointerPrinter - pretty_printers_dict[re.compile('^std::vector<.*>$')] = lambda val: StdVectorPrinter("std::vector", val) + libstdcxx_printer.add('std::basic_string', StdStringPrinter) + libstdcxx_printer.add('std::bitset', StdBitsetPrinter) + libstdcxx_printer.add('std::deque', StdDequePrinter) + libstdcxx_printer.add('std::list', StdListPrinter) + libstdcxx_printer.add('std::map', StdMapPrinter) + libstdcxx_printer.add('std::multimap', StdMapPrinter) + libstdcxx_printer.add('std::multiset', StdSetPrinter) + libstdcxx_printer.add('std::priority_queue', StdStackOrQueuePrinter) + libstdcxx_printer.add('std::queue', StdStackOrQueuePrinter) + libstdcxx_printer.add('std::tuple', StdTuplePrinter) + libstdcxx_printer.add('std::set', StdSetPrinter) + libstdcxx_printer.add('std::stack', StdStackOrQueuePrinter) + libstdcxx_printer.add('std::unique_ptr', UniquePointerPrinter) + libstdcxx_printer.add('std::vector', StdVectorPrinter) # vector # Printer registrations for classes compiled with -D_GLIBCXX_DEBUG. - pretty_printers_dict[re.compile('^std::__debug::bitset<.*>$')] = lambda val: StdBitsetPrinter("std::__debug::bitset", val) - pretty_printers_dict[re.compile('^std::__debug::deque<.*>$')] = lambda val: StdDequePrinter("std::__debug::deque", val) - pretty_printers_dict[re.compile('^std::__debug::list<.*>$')] = lambda val: StdListPrinter("std::__debug::list", val) - pretty_printers_dict[re.compile('^std::__debug::map<.*>$')] = lambda val: StdMapPrinter("std::__debug::map", val) - pretty_printers_dict[re.compile('^std::__debug::multimap<.*>$')] = lambda val: StdMapPrinter("std::__debug::multimap", val) - pretty_printers_dict[re.compile('^std::__debug::multiset<.*>$')] = lambda val: StdSetPrinter("std::__debug::multiset", val) - pretty_printers_dict[re.compile('^std::__debug::priority_queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::__debug::priority_queue", val) - pretty_printers_dict[re.compile('^std::__debug::queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::__debug::queue", val) - pretty_printers_dict[re.compile('^std::__debug::set<.*>$')] = lambda val: StdSetPrinter("std::__debug::set", val) - pretty_printers_dict[re.compile('^std::__debug::stack<.*>$')] = lambda val: StdStackOrQueuePrinter("std::__debug::stack", val) - pretty_printers_dict[re.compile('^std::__debug::unique_ptr<.*>$')] = UniquePointerPrinter - pretty_printers_dict[re.compile('^std::__debug::vector<.*>$')] = lambda val: StdVectorPrinter("std::__debug::vector", val) + libstdcxx_printer.add('std::__debug::bitset', StdBitsetPrinter) + libstdcxx_printer.add('std::__debug::deque', StdDequePrinter) + libstdcxx_printer.add('std::__debug::list', StdListPrinter) + libstdcxx_printer.add('std::__debug::map', StdMapPrinter) + libstdcxx_printer.add('std::__debug::multimap', StdMapPrinter) + libstdcxx_printer.add('std::__debug::multiset', StdSetPrinter) + libstdcxx_printer.add('std::__debug::priority_queue', + StdStackOrQueuePrinter) + libstdcxx_printer.add('std::__debug::queue', StdStackOrQueuePrinter) + libstdcxx_printer.add('std::__debug::set', StdSetPrinter) + libstdcxx_printer.add('std::__debug::stack', StdStackOrQueuePrinter) + libstdcxx_printer.add('std::__debug::unique_ptr', UniquePointerPrinter) + libstdcxx_printer.add('std::__debug::vector', StdVectorPrinter) # These are the TR1 and C++0x printers. # For array - the default GDB pretty-printer seems reasonable. - pretty_printers_dict[re.compile('^std::shared_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::shared_ptr', val) - pretty_printers_dict[re.compile('^std::weak_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::weak_ptr', val) - pretty_printers_dict[re.compile('^std::unordered_map<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::unordered_map', val) - pretty_printers_dict[re.compile('^std::unordered_set<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::unordered_set', val) - pretty_printers_dict[re.compile('^std::unordered_multimap<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::unordered_multimap', val) - pretty_printers_dict[re.compile('^std::unordered_multiset<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::unordered_multiset', val) + libstdcxx_printer.add('std::shared_ptr', StdPointerPrinter) + libstdcxx_printer.add('std::weak_ptr', StdPointerPrinter) + libstdcxx_printer.add('std::unordered_map', Tr1UnorderedMapPrinter) + libstdcxx_printer.add('std::unordered_set', Tr1UnorderedSetPrinter) + libstdcxx_printer.add('std::unordered_multimap', Tr1UnorderedMapPrinter) + libstdcxx_printer.add('std::unordered_multiset', Tr1UnorderedSetPrinter) - pretty_printers_dict[re.compile('^std::tr1::shared_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::tr1::shared_ptr', val) - pretty_printers_dict[re.compile('^std::tr1::weak_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::tr1::weak_ptr', val) - 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) + libstdcxx_printer.add('std::tr1::shared_ptr', StdPointerPrinter) + libstdcxx_printer.add('std::tr1::weak_ptr', StdPointerPrinter) + libstdcxx_printer.add('std::tr1::unordered_map', Tr1UnorderedMapPrinter) + libstdcxx_printer.add('std::tr1::unordered_set', Tr1UnorderedSetPrinter) + libstdcxx_printer.add('std::tr1::unordered_multimap', + Tr1UnorderedMapPrinter) + libstdcxx_printer.add('std::tr1::unordered_multiset', + Tr1UnorderedSetPrinter) # These are the C++0x printer registrations for -D_GLIBCXX_DEBUG cases. # The tr1 namespace printers do not seem to have any debug # equivalents, so do no register them. - pretty_printers_dict[re.compile('^std::__debug::unordered_map<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::__debug::unordered_map', val) - pretty_printers_dict[re.compile('^std::__debug::unordered_set<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::__debug::unordered_set', val) - pretty_printers_dict[re.compile('^std::__debug::unordered_multimap<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::__debug::unordered_multimap', val) - pretty_printers_dict[re.compile('^std::__debug::unordered_multiset<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::__debug:unordered_multiset', val) + libstdcxx_printer.add('std::__debug::unordered_map', + Tr1UnorderedMapPrinter) + libstdcxx_printer.add('std::__debug::unordered_set', + Tr1UnorderedSetPrinter) + libstdcxx_printer.add('std::__debug::unordered_multimap', + Tr1UnorderedMapPrinter) + libstdcxx_printer.add('std::__debug::unordered_multiset', + Tr1UnorderedSetPrinter) # Extensions. - pretty_printers_dict[re.compile('^__gnu_cxx::slist<.*>$')] = StdSlistPrinter + libstdcxx_printer.add('__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("std::_List_iterator",val) - pretty_printers_dict[re.compile('^std::_List_const_iterator<.*>$')] = lambda val: StdListIteratorPrinter("std::_List_const_iterator",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) + libstdcxx_printer.add('std::_List_iterator', StdListIteratorPrinter) + libstdcxx_printer.add('std::_List_const_iterator', + StdListIteratorPrinter) + libstdcxx_printer.add('std::_Rb_tree_iterator', + StdRbtreeIteratorPrinter) + libstdcxx_printer.add('std::_Rb_tree_const_iterator', + StdRbtreeIteratorPrinter) + libstdcxx_printer.add('std::_Deque_iterator', StdDequeIteratorPrinter) + libstdcxx_printer.add('std::_Deque_const_iterator', + StdDequeIteratorPrinter) + libstdcxx_printer.add('__gnu_cxx::__normal_iterator', + StdVectorIteratorPrinter) + libstdcxx_printer.add('__gnu_cxx::_Slist_iterator', + StdSlistIteratorPrinter) - # Debug (compiled with -D_GLIBCXX_DEBUG) printer registrations. - # The Rb_tree debug iterator when unwrapped from the encapsulating __gnu_debug::_Safe_iterator - # does not have the __norm namespace. Just use the existing printer registration for that. - pretty_printers_dict[re.compile('^__gnu_debug::_Safe_iterator<.*>$')] = lambda val: StdDebugIteratorPrinter(val) - pretty_printers_dict[re.compile('^std::__norm::_List_iterator<.*>$')] = lambda val: StdListIteratorPrinter ("std::__norm::_List_iterator",val) - pretty_printers_dict[re.compile('^std::__norm::_List_const_iterator<.*>$')] = lambda val: StdListIteratorPrinter ("std::__norm::_List_const_iterator",val) - pretty_printers_dict[re.compile('^std::__norm::_Deque_const_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val) - pretty_printers_dict[re.compile('^std::__norm::_Deque_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val) + # Debug (compiled with -D_GLIBCXX_DEBUG) printer + # registrations. The Rb_tree debug iterator when unwrapped + # from the encapsulating __gnu_debug::_Safe_iterator does not + # have the __norm namespace. Just use the existing printer + # registration for that. + libstdcxx_printer.add('__gnu_debug::_Safe_iterator', + StdDebugIteratorPrinter) + libstdcxx_printer.add('std::__norm::_List_iterator', + StdListIteratorPrinter) + libstdcxx_printer.add('std::__norm::_List_const_iterator', + StdListIteratorPrinter) + libstdcxx_printer.add('std::__norm::_Deque_const_iterator', + StdDequeIteratorPrinter) + libstdcxx_printer.add('std::__norm::_Deque_iterator', + StdDequeIteratorPrinter) -pretty_printers_dict = {} - build_libstdcxx_dictionary ()