From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 18344 invoked by alias); 26 Feb 2009 23:01:42 -0000 Mailing-List: contact archer-commits-help@sourceware.org; run by ezmlm Sender: Precedence: bulk List-Post: List-Help: List-Subscribe: Received: (qmail 17941 invoked by uid 9674); 26 Feb 2009 23:01:41 -0000 Date: Thu, 26 Feb 2009 23:01:00 -0000 Message-ID: <20090226230139.17374.qmail@sourceware.org> From: jkratoch@sourceware.org To: archer-commits@sourceware.org Subject: [SCM] archer-jankratochvil-python: Merge commit 'origin/archer-tromey-python' into archer-jankratochvil-python X-Git-Refname: refs/heads/archer-jankratochvil-python X-Git-Reftype: branch X-Git-Oldrev: 807b1035c00186e947eab716ffd5d8993b9ca8a8 X-Git-Newrev: 8919c803a68e50c045db5b8f5f88d33c40449139 X-SW-Source: 2009-q1/txt/msg00206.txt.bz2 List-Id: The branch, archer-jankratochvil-python has been updated via 8919c803a68e50c045db5b8f5f88d33c40449139 (commit) via cf7156e5eb72d57a6b886dfe862705fc210f6f67 (commit) via b5235efef9aa1d619d8a5defc5aa1219dff76d3d (commit) via 9f534e722211caffa7caef5cd11c5da2ac24f6c4 (commit) via 6b43f0eaec652104bcbf802d7a86869d956ce4e4 (commit) via f17c887e8b4aa77c8a49885a0f8bf2dab0dba228 (commit) from 807b1035c00186e947eab716ffd5d8993b9ca8a8 (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email. - Log ----------------------------------------------------------------- commit 8919c803a68e50c045db5b8f5f88d33c40449139 Merge: 807b1035c00186e947eab716ffd5d8993b9ca8a8 cf7156e5eb72d57a6b886dfe862705fc210f6f67 Author: Jan Kratochvil Date: Fri Feb 27 00:01:17 2009 +0100 Merge commit 'origin/archer-tromey-python' into archer-jankratochvil-python ----------------------------------------------------------------------- Summary of changes: gdb/doc/gdb.texinfo | 69 +++++--- gdb/python/lib/gdb/libstdcxx/v6/printers.py | 114 ++++++++---- gdb/python/python-internal.h | 6 +- gdb/python/python-membuf.c | 2 +- gdb/python/python-objfile.c | 12 +- gdb/python/python-type.c | 13 ++- gdb/python/python-utils.c | 16 ++- gdb/python/python.c | 234 +++++++++++------------- gdb/testsuite/gdb.python/python-prettyprint.py | 76 ++++++-- gdb/varobj.c | 108 ++++++----- 10 files changed, 379 insertions(+), 271 deletions(-) First 500 lines of diff: diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 35461a9..4f27cdf 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -18593,6 +18593,11 @@ target's @code{char} type will be an 8-bit byte. However, on some unusual platforms, this type may have a different size. @end defmethod +@defmethod Type strip_typedefs +Return a new @code{gdb.Type} that represents the real type, +after removing all layers of typedefs. +@end defmethod + @defmethod Type tag Return the tag name for this type. The tag name is the name after @code{struct}, @code{union}, or @code{enum} in C; not all languages @@ -18853,30 +18858,27 @@ convertible to @code{gdb.Value}, an exception is raised. @subsubsection Selecting Pretty-Printers -The Python dictionary @code{gdb.pretty_printers} maps regular -expressions (strings) onto constructors. Each @code{gdb.Objfile} also -contains a @code{pretty_printers} attribute. A constructor, in this -context, is a function which takes a single @code{gdb.Value} argument -and returns a a pretty-printer conforming to the interface definition -above. +The Python list @code{gdb.pretty_printers} contains an array of +functions that have been registered via addition as a pretty-printer. +Each function will be called with a @code{gdb.Value} to be +pretty-printed. Each @code{gdb.Objfile} also contains a +@code{pretty_printers} attribute. A function on one of these lists +takes a single @code{gdb.Value} argument and returns a pretty-printer +object conforming to the interface definition above. If this function +cannot create a pretty-printer for the value, it should return +@code{None}. -When printing a value, @value{GDBN} first computes the value's -canonical type by following typedefs, following a reference type to -its referenced type, and removing qualifiers, such as @code{const} or -@code{volatile}. - -Then, @value{GDBN} tests each regular expression against this type name. @value{GDBN} first checks the @code{pretty_printers} attribute of each -@code{gdb.Objfile}; after these have been exhausted it tries the -global @code{gdb.pretty_printers}. - -If a regular expression matches, then the corresponding pretty-printer -is invoked with a @code{gdb.Value} representing the value to be -printed. +@code{gdb.Objfile} and iteratively calls each function in the list for +that @code{gdb.Objfile} until it receives a pretty-printer object. +After these @code{gdb.Objfile} have been exhausted, it tries the +global @code{gdb.pretty-printers} list, again calling each function +until an object is returned. The order in which the objfiles are searched is not specified. -Similarly, the order in which the regular expressions in a given -dictionary are tried is not specified. +Functions are always invoked from the head of the +@code{gdb.pretty-printers} list, and iterated over sequentially until +the end of the list, or a printer object is returned. Here is an example showing how a @code{std::string} printer might be written: @@ -18885,13 +18887,34 @@ written: class StdStringPrinter: "Print a std::string" - def __init__(self, val): + def __init__ (self, val): self.val = val - def to_string(self): + def to_string (self): return self.val['_M_dataplus']['_M_p'] @end smallexample +And here is an example showing how a lookup function for +the printer example above might be written. + +@smallexample +def str_lookup_function (val): + + lookup_tag = val.type ().tag () + regex = re.compile ("^std::basic_string$") + if lookup_tag == None: + return None + if regex.match (lookup_tag): + return StdStringPrinter (val) + + return None +@end smallexample + +The example lookup function extracts the value's type, and attempts to +match it to a type that it can pretty-print. If it is a type the +printer can pretty-print, it will return a printer object. If not, it +returns: @code{None}. + We recommend that you put your core pretty-printers into a versioned python package, and then restrict your auto-loaded code to idempotent behavior -- for example, just @code{import}s of your printer modules, @@ -18904,7 +18927,7 @@ For example, in addition to the above, this code might appear in @smallexample def register_printers (objfile): - objfile.pretty_printers['^std::basic_string$'] = StdStringPrinter + objfile.pretty_printers.add (str_lookup_function) @end smallexample And then the corresponding contents of the auto-load file would be: diff --git a/gdb/python/lib/gdb/libstdcxx/v6/printers.py b/gdb/python/lib/gdb/libstdcxx/v6/printers.py index 508a22d..7a77ad4 100644 --- a/gdb/python/lib/gdb/libstdcxx/v6/printers.py +++ b/gdb/python/lib/gdb/libstdcxx/v6/printers.py @@ -1,6 +1,6 @@ # Pretty-printers for libstc++. -# Copyright (C) 2008 Free Software Foundation, Inc. +# 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 @@ -17,6 +17,7 @@ import gdb import itertools +import re class StdPointerPrinter: "Print a smart pointer of some kind" @@ -337,7 +338,16 @@ class StdBitsetPrinter: def children (self): words = self.val['_M_w'] wtype = words.type() - tsize = wtype.target().sizeof() + + # 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 @@ -548,56 +558,90 @@ class Tr1UnorderedMapPrinter: def display_hint (self): return 'map' -def register_libstdcxx_printers(obj): +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 - obj.pretty_printers['^std::basic_string$'] = lambda val: StdStringPrinter(None, val) - obj.pretty_printers['^std::basic_string$'] = lambda val: StdStringPrinter(target_wide_charset, val) - obj.pretty_printers['^std::basic_string$'] = lambda val: StdStringPrinter('UTF-16', val) - obj.pretty_printers['^std::basic_string$'] = lambda val: StdStringPrinter('UTF-32', val) - obj.pretty_printers['^std::bitset<.*>$'] = StdBitsetPrinter - obj.pretty_printers['^std::deque<.*>$'] = StdDequePrinter - obj.pretty_printers['^std::list<.*>$'] = StdListPrinter - obj.pretty_printers['^std::map<.*>$'] = lambda val: StdMapPrinter("std::map", val) - obj.pretty_printers['^std::multimap<.*>$'] = lambda val: StdMapPrinter("std::multimap", val) - obj.pretty_printers['^std::multiset<.*>$'] = lambda val: StdSetPrinter("std::multiset", val) - obj.pretty_printers['^std::priority_queue<.*>$'] = lambda val: StdStackOrQueuePrinter("std::priority_queue", val) - obj.pretty_printers['^std::queue<.*>$'] = lambda val: StdStackOrQueuePrinter("std::queue", val) - obj.pretty_printers['^std::set<.*>$'] = lambda val: StdSetPrinter("std::set", val) - obj.pretty_printers['^std::stack<.*>$'] = lambda val: StdStackOrQueuePrinter("std::stack", val) - obj.pretty_printers['^std::vector<.*>$'] = StdVectorPrinter + pretty_printers_dict[re.compile('^std::basic_string$')] = lambda val: StdStringPrinter(None, val) + pretty_printers_dict[re.compile('^std::basic_string$')] = lambda val: StdStringPrinter(target_wide_charset, val) + pretty_printers_dict[re.compile('^std::basic_string$')] = lambda val: StdStringPrinter('UTF-16', val) + pretty_printers_dict[re.compile('^std::basic_string$')] = 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 # C++0x stuff. # array - the default seems reasonable # smart_ptr? seems to only be in boost right now - obj.pretty_printers['^std::tr1::shared_ptr<.*>$'] = lambda val: StdPointerPrinter ('std::shared_ptr', val) - obj.pretty_printers['^std::tr1::weak_ptr<.*>$'] = lambda val: StdPointerPrinter ('std::weak_ptr', val) - obj.pretty_printers['^std::tr1::unique_ptr<.*>$'] = UniquePointerPrinter - obj.pretty_printers['^std::tr1::unordered_map<.*>$'] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_map', val) - obj.pretty_printers['^std::tr1::unordered_set<.*>$'] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_set', val) - obj.pretty_printers['^std::tr1::unordered_multimap<.*>$'] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_multimap', val) - obj.pretty_printers['^std::tr1::unordered_multiset<.*>$'] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_multiset', val) + 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. - obj.pretty_printers['^__gnu_cxx::slist<.*>$'] = StdSlistPrinter + 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. - obj.pretty_printers['^std::_List_iterator<.*>$'] = lambda val: StdListIteratorPrinter(val) - obj.pretty_printers['^std::_List_const_iterator<.*>$'] = lambda val: StdListIteratorPrinter(val) - obj.pretty_printers['^std::_Rb_tree_iterator<.*>$'] = lambda val: StdRbtreeIteratorPrinter(val) - obj.pretty_printers['^std::_Rb_tree_const_iterator<.*>$'] = lambda val: StdRbtreeIteratorPrinter(val) - obj.pretty_printers['^std::_Deque_iterator<.*>$'] = lambda val: StdDequeIteratorPrinter(val) - obj.pretty_printers['^std::_Deque_const_iterator<.*>$'] = lambda val: StdDequeIteratorPrinter(val) - obj.pretty_printers['^__gnu_cxx::__normal_iterator<.*>$'] = lambda val: StdVectorIteratorPrinter(val) - obj.pretty_printers['^__gnu_cxx::_Slist_iterator<.*>$'] = lambda val: StdSlistIteratorPrinter(val) - + 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 () register_libstdcxx_printers (gdb.current_objfile()) diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 0608330..12422af 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -161,10 +161,10 @@ int gdbpy_is_value_object (PyObject *obj); /* Note that these are declared here, and not in python.h with the other pretty-printer functions, because they refer to PyObject. */ -char *apply_varobj_pretty_printer (PyObject *print_obj, struct value *value, +char *apply_varobj_pretty_printer (PyObject *print_obj, struct value **replacement); -PyObject *gdbpy_get_varobj_pretty_printer (struct type *type); -PyObject *gdbpy_instantiate_printer (PyObject *cons, struct value *value); +PyObject *gdbpy_get_varobj_pretty_printer (struct value *value); +PyObject *gdbpy_instantiate_printer (PyObject *cons, PyObject *value); char *gdbpy_get_display_hint (PyObject *printer); extern PyObject *gdbpy_children_cst; diff --git a/gdb/python/python-membuf.c b/gdb/python/python-membuf.c index d8a8183..04bf3b4 100644 --- a/gdb/python/python-membuf.c +++ b/gdb/python/python-membuf.c @@ -165,7 +165,7 @@ get_seg_count (PyObject *self, Py_ssize_t *lenp) Py_ssize_t get_char_buffer (PyObject *self, Py_ssize_t segment, char **ptrptr) { - void *ptr; + void *ptr = NULL; Py_ssize_t ret; ret = get_read_buffer (self, segment, &ptr); diff --git a/gdb/python/python-objfile.c b/gdb/python/python-objfile.c index a225409..e97d3a2 100644 --- a/gdb/python/python-objfile.c +++ b/gdb/python/python-objfile.c @@ -1,6 +1,6 @@ /* Python interface to objfiles. - Copyright (C) 2008 Free Software Foundation, Inc. + Copyright (C) 2008, 2009 Free Software Foundation, Inc. This file is part of GDB. @@ -29,7 +29,7 @@ typedef struct /* The corresponding objfile. */ struct objfile *objfile; - /* The pretty-printer dictionary. */ + /* The pretty-printer list of functions. */ PyObject *printers; } objfile_object; @@ -66,7 +66,7 @@ objfpy_new (PyTypeObject *type, PyObject *args, PyObject *keywords) { self->objfile = NULL; - self->printers = PyDict_New (); + self->printers = PyList_New (0); if (!self->printers) { Py_DECREF (self); @@ -95,10 +95,10 @@ objfpy_set_printers (PyObject *o, PyObject *value, void *ignore) return -1; } - if (! PyDict_Check (value)) + if (! PyList_Check (value)) { PyErr_SetString (PyExc_TypeError, - "the pretty_printers attribute must be a dictionary"); + "the pretty_printers attribute must be a list"); return -1; } @@ -139,7 +139,7 @@ objfile_to_objfile_object (struct objfile *objfile) object->objfile = objfile; - object->printers = PyDict_New (); + object->printers = PyList_New (0); if (!object->printers) { Py_DECREF (object); diff --git a/gdb/python/python-type.c b/gdb/python/python-type.c index 7396bad..c39ff27 100644 --- a/gdb/python/python-type.c +++ b/gdb/python/python-type.c @@ -1,6 +1,6 @@ /* Python interface to types. - Copyright (C) 2008 Free Software Foundation, Inc. + Copyright (C) 2008, 2009 Free Software Foundation, Inc. This file is part of GDB. @@ -234,6 +234,15 @@ typy_tag (PyObject *self, PyObject *args) return PyString_FromString (TYPE_TAG_NAME (type)); } +/* Return the type, stripped of typedefs. */ +static PyObject * +typy_strip_typedefs (PyObject *self, PyObject *args) +{ + struct type *type = ((type_object *) self)->type; + + return type_to_type_object (check_typedef (type)); +} + /* Return a Type object which represents a pointer to SELF. */ static PyObject * typy_pointer (PyObject *self, PyObject *args) @@ -712,6 +721,8 @@ Each field is a dictionary." }, "Return the size of this type, in bytes" }, { "tag", typy_tag, METH_NOARGS, "Return the tag name for this type, or None." }, + { "strip_typedefs", typy_strip_typedefs, METH_NOARGS, + "Return a type stripped of typedefs"}, { "target", typy_target, METH_NOARGS, "Return the target type of this type" }, { "template_argument", typy_template_argument, METH_VARARGS, diff --git a/gdb/python/python-utils.c b/gdb/python/python-utils.c index c6c305f..f9c9486 100644 --- a/gdb/python/python-utils.c +++ b/gdb/python/python-utils.c @@ -82,7 +82,11 @@ python_string_to_unicode (PyObject *obj) /* If obj is already a unicode string, just return it. I wish life was always that simple... */ if (PyUnicode_Check (obj)) - unicode_str = obj; + { + unicode_str = obj; + Py_INCREF (obj); + } + else if (PyString_Check (obj)) unicode_str = PyUnicode_FromEncodedObject (obj, host_charset (), NULL); else @@ -137,12 +141,15 @@ char * python_string_to_target_string (PyObject *obj) { PyObject *str; + char *result; str = python_string_to_unicode (obj); if (str == NULL) return NULL; - return unicode_to_target_string (str); + result = unicode_to_target_string (str); + Py_DECREF (str); + return result; } /* Converts a python string (8-bit or unicode) to a target string in @@ -153,12 +160,15 @@ char * python_string_to_host_string (PyObject *obj) { PyObject *str; + char *result; str = python_string_to_unicode (obj); if (str == NULL) return NULL; - return unicode_to_encoded_string (str, host_charset ()); + result = unicode_to_encoded_string (str, host_charset ()); + Py_DECREF (str); + return result; } /* Converts a target string of LENGTH bytes in the target's charset to a diff --git a/gdb/python/python.c b/gdb/python/python.c index 99f9f40..a816fc5 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -1056,75 +1056,48 @@ gdbpy_objfiles (PyObject *unused1, PyObject *unused2) -/* Return a string representing TYPE. */ -static char * -get_type (struct type *type) -{ - struct cleanup *old_chain; - struct ui_file *stb; - char *thetype; - long length; - - stb = mem_fileopen (); - old_chain = make_cleanup_ui_file_delete (stb); - - CHECK_TYPEDEF (type); - - type_print (type, "", stb, -1); - - thetype = ui_file_xstrdup (stb, &length); - do_cleanups (old_chain); - return thetype; -} - /* Helper function for find_pretty_printer which iterates over a - dictionary and tries to find a match. */ + list, calls each function and inspects output. */ static PyObject * -search_pp_dictionary (PyObject *dict, char *type_name) +search_pp_list (PyObject *list, PyObject *value) { - Py_ssize_t iter; - PyObject *key, *func, *found = NULL; - - /* See if the type matches a pretty-printer regexp. */ - iter = 0; - while (! found && PyDict_Next (dict, &iter, &key, &func)) + Py_ssize_t pp_list_size, list_index; + PyObject *function, *printer = NULL; + + pp_list_size = PyList_Size (list); + for (list_index = 0; list_index < pp_list_size; list_index++) { - char *rx_str; + function = PyList_GetItem (list, list_index); + if (! function) + return NULL; - if (! PyString_Check (key)) - continue; - rx_str = PyString_AsString (key); - if (re_comp (rx_str) == NULL && re_exec (type_name) == 1) hooks/post-receive -- Repository for Project Archer.