From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22226 invoked by alias); 22 Nov 2008 01:39:00 -0000 Mailing-List: contact archer-commits-help@sourceware.org; run by ezmlm Sender: Precedence: bulk List-Post: List-Help: List-Subscribe: Received: (qmail 22195 invoked by uid 306); 22 Nov 2008 01:38:59 -0000 Date: Sat, 22 Nov 2008 01:39:00 -0000 Message-ID: <20081122013859.22180.qmail@sourceware.org> From: tromey@sourceware.org To: archer-commits@sourceware.org Subject: [SCM] archer-tromey-python: * python/lib/gdb/libstdcxx/v6/printers.py: New file. X-Git-Refname: refs/heads/archer-tromey-python X-Git-Reftype: branch X-Git-Oldrev: 6c35e923d5ba223e01f943798d9d093f58acf3da X-Git-Newrev: e991a85b6bc0ec175e1d0357f10d74c5dd60780a X-SW-Source: 2008-q4/txt/msg00146.txt.bz2 List-Id: The branch, archer-tromey-python has been updated via e991a85b6bc0ec175e1d0357f10d74c5dd60780a (commit) from 6c35e923d5ba223e01f943798d9d093f58acf3da (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email. - Log ----------------------------------------------------------------- commit e991a85b6bc0ec175e1d0357f10d74c5dd60780a Author: Tom Tromey Date: Fri Nov 21 18:38:39 2008 -0700 * python/lib/gdb/libstdcxx/v6/printers.py: New file. * python/python.c (_initialize_python): Conditionally define gdb.datadir. Correctly update sys.path. Set gdb.__path__. * configure: Rebuild. * configure.ac: Update CONFIG_INSTALL and CONFIG_UNINSTALL for Python. * Makefile.in (PY_FILES): New variable. (install-python): New target. (uninstall-python): Likewise. (PY_DIRS): New variable. ----------------------------------------------------------------------- Summary of changes: gdb/ChangeLog | 13 + gdb/Makefile.in | 29 ++ gdb/configure | 2 + gdb/configure.ac | 2 + gdb/python/lib/gdb/libstdcxx/v6/printers.py | 522 +++++++++++++++++++++++++++ gdb/python/python.c | 7 +- 6 files changed, 573 insertions(+), 2 deletions(-) create mode 100644 gdb/python/lib/gdb/libstdcxx/v6/printers.py First 500 lines of diff: diff --git a/gdb/ChangeLog b/gdb/ChangeLog index cf899c5..8b15a01 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,18 @@ 2008-11-21 Tom Tromey + * python/lib/gdb/libstdcxx/v6/printers.py: New file. + * python/python.c (_initialize_python): Conditionally define + gdb.datadir. Correctly update sys.path. Set gdb.__path__. + * configure: Rebuild. + * configure.ac: Update CONFIG_INSTALL and CONFIG_UNINSTALL for + Python. + * Makefile.in (PY_FILES): New variable. + (install-python): New target. + (uninstall-python): Likewise. + (PY_DIRS): New variable. + +2008-11-21 Tom Tromey + * python/python.c (get_parameter): Use var_type, not type. 2008-11-21 Tom Tromey diff --git a/gdb/Makefile.in b/gdb/Makefile.in index e60a504..79a9d1c 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1913,6 +1913,35 @@ python-value.o: $(srcdir)/python/python-value.c $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python-value.c $(POSTCOMPILE) +# All Python install directories. These must be sorted, shallowest +# first. These are maintained by hand because that is simpler than +# writing portable sh to make the __init__.py files, and the result is +# faster. +PY_DIRS = gdb gdb/libstdcxx gdb/libstdcxx/v6 + +# All python library files, with the "python/lib" stripped off. +# Note that we should only install files in the "gdb" module. +PY_FILES = gdb/libstdcxx/v6/printers.py + +# Install the Python library. Python library files go under +# $(GDB_DATADIR_PATH)/python. We create a dummy __init__.py for +# each directory, to make importing work properly. If there is a real +# __init__.py in PY_FILES, it will overwrite the dummy file. +install-python: + dirs='$(PY_DIRS)'; for dir in $$dirs; do \ + $(SHELL) $(srcdir)/../mkinstalldirs $(DESTDIR)$(GDB_DATADIR_PATH)/python/$$dir; \ + if ! test -f $(DESTDIR)$(GDB_DATADIR_PATH)/python/$$dir/__init__.py; then \ + echo > $(DESTDIR)$(GDB_DATADIR_PATH)/python/$$dir/__init__.py; \ + fi; \ + done; \ + files='$(PY_FILES)'; for file in $$files; do \ + $(INSTALL_DATA) $(srcdir)/python/lib/$$file $(DESTDIR)$(GDB_DATADIR_PATH)/python/$$file; \ + done + +# Brute force. +uninstall-python: + rm -rf $(DESTDIR)/$(GDB_DATADIR_PATH)/python + # # Dependency tracking. Most of this is conditional on GNU Make being # found by configure; if GNU Make is not found, we fall back to a diff --git a/gdb/configure b/gdb/configure index a3cc179..13ebfae 100755 --- a/gdb/configure +++ b/gdb/configure @@ -11739,6 +11739,8 @@ _ACEOF CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_PYTHON_OBS)" CONFIG_DEPS="$CONFIG_DEPS \$(SUBDIR_PYTHON_DEPS)" CONFIG_SRCS="$CONFIG_SRCS \$(SUBDIR_PYTHON_SRCS)" + CONFIG_INSTALL="$CONFIG_INSTALL install-python" + CONFIG_UNINSTALL="$CONFIG_UNINSTALL uninstall-python" ENABLE_CFLAGS="$ENABLE_CFLAGS \$(SUBDIR_PYTHON_CFLAGS)" # Flags needed to compile Python code (taken from python-config --cflags). diff --git a/gdb/configure.ac b/gdb/configure.ac index 77e2f6c..08e0af8 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -681,6 +681,8 @@ if test "${have_libpython}" = yes; then CONFIG_OBS="$CONFIG_OBS \$(SUBDIR_PYTHON_OBS)" CONFIG_DEPS="$CONFIG_DEPS \$(SUBDIR_PYTHON_DEPS)" CONFIG_SRCS="$CONFIG_SRCS \$(SUBDIR_PYTHON_SRCS)" + CONFIG_INSTALL="$CONFIG_INSTALL install-python" + CONFIG_UNINSTALL="$CONFIG_UNINSTALL uninstall-python" ENABLE_CFLAGS="$ENABLE_CFLAGS \$(SUBDIR_PYTHON_CFLAGS)" # Flags needed to compile Python code (taken from python-config --cflags). diff --git a/gdb/python/lib/gdb/libstdcxx/v6/printers.py b/gdb/python/lib/gdb/libstdcxx/v6/printers.py new file mode 100644 index 0000000..d25b4db --- /dev/null +++ b/gdb/python/lib/gdb/libstdcxx/v6/printers.py @@ -0,0 +1,522 @@ +# Pretty-printers for libstc++. + +# Copyright (C) 2008 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 . + +import gdb +import itertools + +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 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 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 'whatever' + +class StdStackOrQueuePrinter: + "Print a std::stack or std::queue" + + def __init__ (self, typename, val): + self.typename = typename + self.visualizer = gdb.get_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()) + +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 + +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) + valuetype = self.val.type().template_argument(1) + nodetype = gdb.Type('std::_Rb_tree_node< std::pair< const %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() + tsize = wtype.target().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) + +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.get_parameter('target-charset') + elif isinstance(encoding, WideEncoding): + encoding = encoding.value + return self.val['_M_dataplus']['_M_p'].string(encoding) + +class Tr1HashtableIterator: + def __init__ (self, hash): + self.count = 0 + self.n_buckets = hash['_M_bucket_count'] + if self.n_buckets == 0: + self.node = False + else: + self.bucket = hash['_M_buckets'] + self.node = self.bucket[0] + self.update () hooks/post-receive -- Repository for Project Archer.