diff mbox

RFC: Make iterator printers fail more gracefully

Message ID 20161215173917.GA12231@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely Dec. 15, 2016, 5:39 p.m. UTC
This patch tries to improve the user experience when debugging
container iterators, for cases where some of the typedefs used by the
printers are not in the debuginfo, so gdb.lookup_type() calls fail.
That happens if the iterator's operator*() and operator->() haven't
been instantiated, or if they've been inlined.

Currently this results in an exception:

$1 = Python Exception <class 'ValueError'> Cannot find type std::_List_iterator<int>::_Node: 

If the iterator being printed is part of some other object the whole
thing fails due to the exception.

With this patch the iterator instead prints:

$1 = <insufficient debuginfo for std::list iterator>

and if it's a subobject the rest of the object is printed, with that
as the value of the iterator.

	* python/libstdcxx/v6/printers.py (StdListIteratorPrinter.to_string):
	Handle exception from failed type lookup and return user-friendly
	string.
	(StdRbtreeIteratorPrinter.__init__): Handle exception from failed
	type lookup.
	(StdRbtreeIteratorPrinter.to_string): Return user-friendly string.

Seem reasonable?

I consider this a stop-gap until we have Xmethods for all our iterator
types, then we'll be able to "print *iter" even without debuginfo for
all the iterator's members, and we can disable these printers.
commit 1794ede023b36df4eb2c7264e2d04d6a86ad456a
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Thu Dec 15 16:52:21 2016 +0000

    Make iterator printers fail more gracefully
    
    	* python/libstdcxx/v6/printers.py (StdListIteratorPrinter.to_string):
    	Handle exception from failed type lookup and return user-friendly
    	string.
    	(StdRbtreeIteratorPrinter.__init__): Handle exception from failed
    	type lookup.
    	(StdRbtreeIteratorPrinter.to_string): Return user-friendly string.

Comments

Ville Voutilainen Dec. 15, 2016, 5:46 p.m. UTC | #1
On 15 December 2016 at 19:39, Jonathan Wakely <jwakely@redhat.com> wrote:
> This patch tries to improve the user experience when debugging
> container iterators, for cases where some of the typedefs used by the
> printers are not in the debuginfo, so gdb.lookup_type() calls fail.
> That happens if the iterator's operator*() and operator->() haven't
> been instantiated, or if they've been inlined.
>
> Currently this results in an exception:
>
> $1 = Python Exception <class 'ValueError'> Cannot find type
> std::_List_iterator<int>::_Node:
> If the iterator being printed is part of some other object the whole
> thing fails due to the exception.
>
> With this patch the iterator instead prints:
>
> $1 = <insufficient debuginfo for std::list iterator>
>
> and if it's a subobject the rest of the object is printed, with that
> as the value of the iterator.
>
>         * python/libstdcxx/v6/printers.py
> (StdListIteratorPrinter.to_string):
>         Handle exception from failed type lookup and return user-friendly
>         string.
>         (StdRbtreeIteratorPrinter.__init__): Handle exception from failed
>         type lookup.
>         (StdRbtreeIteratorPrinter.to_string): Return user-friendly string.
>
> Seem reasonable?

Yes, looks like a good improvement.

> I consider this a stop-gap until we have Xmethods for all our iterator
> types, then we'll be able to "print *iter" even without debuginfo for
> all the iterator's members, and we can disable these printers.


+1.
David Malcolm Dec. 15, 2016, 6:11 p.m. UTC | #2
On Thu, 2016-12-15 at 17:39 +0000, Jonathan Wakely wrote:
> This patch tries to improve the user experience when debugging
> container iterators, for cases where some of the typedefs used by the
> printers are not in the debuginfo, so gdb.lookup_type() calls fail.
> That happens if the iterator's operator*() and operator->() haven't
> been instantiated, or if they've been inlined.
> 
> Currently this results in an exception:
> 
> $1 = Python Exception <class 'ValueError'> Cannot find type
> std::_List_iterator<int>::_Node: 
> 
> If the iterator being printed is part of some other object the whole
> thing fails due to the exception.
> 
> With this patch the iterator instead prints:
> 
> $1 = <insufficient debuginfo for std::list iterator>
> 
> and if it's a subobject the rest of the object is printed, with that
> as the value of the iterator.
> 
> 	* python/libstdcxx/v6/printers.py
> (StdListIteratorPrinter.to_string):
> 	Handle exception from failed type lookup and return user
> -friendly
> 	string.
> 	(StdRbtreeIteratorPrinter.__init__): Handle exception from
> failed
> 	type lookup.
> 	(StdRbtreeIteratorPrinter.to_string): Return user-friendly
> string.
> 
> Seem reasonable?
> 
> I consider this a stop-gap until we have Xmethods for all our
> iterator
> types, then we'll be able to "print *iter" even without debuginfo for
> all the iterator's members, and we can disable these printers.

BTW, is it always a ValueError exception?

(I'm a little wary of naked "except:" in Python, as it can catch
*anything*, including syntax errors in the try/except-guarded code).
Jonathan Wakely Dec. 15, 2016, 6:29 p.m. UTC | #3
On 15/12/16 13:11 -0500, David Malcolm wrote:
>On Thu, 2016-12-15 at 17:39 +0000, Jonathan Wakely wrote:
>> This patch tries to improve the user experience when debugging
>> container iterators, for cases where some of the typedefs used by the
>> printers are not in the debuginfo, so gdb.lookup_type() calls fail.
>> That happens if the iterator's operator*() and operator->() haven't
>> been instantiated, or if they've been inlined.
>>
>> Currently this results in an exception:
>>
>> $1 = Python Exception <class 'ValueError'> Cannot find type
>> std::_List_iterator<int>::_Node:
>>
>> If the iterator being printed is part of some other object the whole
>> thing fails due to the exception.
>>
>> With this patch the iterator instead prints:
>>
>> $1 = <insufficient debuginfo for std::list iterator>
>>
>> and if it's a subobject the rest of the object is printed, with that
>> as the value of the iterator.
>>
>> 	* python/libstdcxx/v6/printers.py
>> (StdListIteratorPrinter.to_string):
>> 	Handle exception from failed type lookup and return user
>> -friendly
>> 	string.
>> 	(StdRbtreeIteratorPrinter.__init__): Handle exception from
>> failed
>> 	type lookup.
>> 	(StdRbtreeIteratorPrinter.to_string): Return user-friendly
>> string.
>>
>> Seem reasonable?
>>
>> I consider this a stop-gap until we have Xmethods for all our
>> iterator
>> types, then we'll be able to "print *iter" even without debuginfo for
>> all the iterator's members, and we can disable these printers.
>
>BTW, is it always a ValueError exception?
>
>(I'm a little wary of naked "except:" in Python, as it can catch
>*anything*, including syntax errors in the try/except-guarded code).

Good point. As far as I know, the gdb.lookup_type method will throw a
ValueError in the case I'm trying to fix. If it can throw other things
we can deal with them later by adding other handlers.
diff mbox

Patch

diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 86de1ca..60afb52 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -202,10 +202,13 @@  class StdListIteratorPrinter:
     def to_string(self):
         if not self.val['_M_node']:
             return 'non-dereferenceable iterator for std::list'
-        nodetype = find_type(self.val.type, '_Node')
-        nodetype = nodetype.strip_typedefs().pointer()
-        node = self.val['_M_node'].cast(nodetype).dereference()
-        return str(get_value_from_list_node(node))
+        try:
+            nodetype = find_type(self.val.type, '_Node')
+            nodetype = nodetype.strip_typedefs().pointer()
+            node = self.val['_M_node'].cast(nodetype).dereference()
+            return str(get_value_from_list_node(node))
+        except:
+            return '<insufficient debuginfo for std::list iterator>'
 
 class StdSlistPrinter:
     "Print a __gnu_cxx::slist"
@@ -496,12 +499,17 @@  class StdRbtreeIteratorPrinter:
     def __init__ (self, typename, val):
         self.val = val
         valtype = self.val.type.template_argument(0).strip_typedefs()
-        nodetype = gdb.lookup_type('std::_Rb_tree_node<' + str(valtype) + '>')
-        self.link_type = nodetype.strip_typedefs().pointer()
+        try:
+            nodetype = gdb.lookup_type('std::_Rb_tree_node<' + str(valtype) + '>')
+            self.link_type = nodetype.strip_typedefs().pointer()
+        except:
+            self.link_type = None
 
     def to_string (self):
         if not self.val['_M_node']:
             return 'non-dereferenceable iterator for associative container'
+        if self.link_type is None:
+            return "<insufficient debuginfo for associative container iterator>"
         node = self.val['_M_node'].cast(self.link_type).dereference()
         return str(get_value_from_Rb_tree_node(node))