1 # Pretty-printers for libstc++.
3 # Copyright (C) 2008, 2009 Free Software Foundation, Inc.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 class StdPointerPrinter:
23 "Print a smart pointer of some kind"
25 def __init__ (self, typename, val):
26 self.typename = typename
30 if self.val['_M_refcount']['_M_pi'] == 0:
31 return '%s (empty) %s' % (self.typename, self.val['_M_ptr'])
32 return '%s (count %d) %s' % (self.typename,
33 self.val['_M_refcount']['_M_pi']['_M_use_count'],
36 class UniquePointerPrinter:
39 def __init__ (self, val):
43 return self.val['_M_t']
49 def __init__(self, nodetype, head):
50 self.nodetype = nodetype
51 self.base = head['_M_next']
52 self.head = head.address
59 if self.base == self.head:
61 elt = self.base.cast(self.nodetype).dereference()
62 self.base = elt['_M_next']
64 self.count = self.count + 1
65 return ('[%d]' % count, elt['_M_data'])
67 def __init__(self, val):
71 itype = self.val.type.template_argument(0)
72 nodetype = gdb.lookup_type('std::_List_node<%s>' % itype).pointer()
73 return self._iterator(nodetype, self.val['_M_impl']['_M_node'])
76 if self.val['_M_impl']['_M_node'].address == self.val['_M_impl']['_M_node']['_M_next']:
77 return 'empty std::list'
80 class StdListIteratorPrinter:
81 "Print std::list::iterator"
83 def __init__(self, val):
87 itype = self.val.type.template_argument(0)
88 nodetype = gdb.lookup_type('std::_List_node<%s>' % itype).pointer()
89 return self.val['_M_node'].cast(nodetype).dereference()['_M_data']
91 class StdSlistPrinter:
92 "Print a __gnu_cxx::slist"
95 def __init__(self, nodetype, head):
96 self.nodetype = nodetype
97 self.base = head['_M_head']['_M_next']
106 elt = self.base.cast(self.nodetype).dereference()
107 self.base = elt['_M_next']
109 self.count = self.count + 1
110 return ('[%d]' % count, elt['_M_data'])
112 def __init__(self, val):
116 itype = self.val.type.template_argument(0)
117 nodetype = gdb.lookup_type('__gnu_cxx::_Slist_node<%s>' % itype).pointer()
118 return self._iterator(nodetype, self.val)
121 if self.val['_M_head']['_M_next'] == 0:
122 return 'empty __gnu_cxx::slist'
123 return '__gnu_cxx::slist'
125 class StdSlistIteratorPrinter:
126 "Print __gnu_cxx::slist::iterator"
128 def __init__(self, val):
132 itype = self.val.type.template_argument(0)
133 nodetype = gdb.lookup_type('__gnu_cxx::_Slist_node<%s>' % itype).pointer()
134 return self.val['_M_node'].cast(nodetype).dereference()['_M_data']
136 class StdVectorPrinter:
137 "Print a std::vector"
140 def __init__ (self, start, finish):
149 if self.item == self.finish:
152 self.count = self.count + 1
153 elt = self.item.dereference()
154 self.item = self.item + 1
155 return ('[%d]' % count, elt)
157 def __init__(self, val):
161 return self._iterator(self.val['_M_impl']['_M_start'],
162 self.val['_M_impl']['_M_finish'])
165 start = self.val['_M_impl']['_M_start']
166 finish = self.val['_M_impl']['_M_finish']
167 end = self.val['_M_impl']['_M_end_of_storage']
168 return ('std::vector of length %d, capacity %d'
169 % (int (finish - start), int (end - start)))
171 def display_hint(self):
174 class StdVectorIteratorPrinter:
175 "Print std::vector::iterator"
177 def __init__(self, val):
181 return self.val['_M_current'].dereference()
183 class StdStackOrQueuePrinter:
184 "Print a std::stack or std::queue"
186 def __init__ (self, typename, val):
187 self.typename = typename
188 self.visualizer = gdb.default_visualizer(val['c'])
191 return self.visualizer.children()
193 def to_string (self):
194 return '%s wrapping: %s' % (self.typename,
195 self.visualizer.to_string())
197 def display_hint (self):
198 if hasattr (self.visualizer, 'display_hint'):
199 return self.visualizer.display_hint ()
202 class RbtreeIterator:
203 def __init__(self, rbtree):
204 self.size = rbtree['_M_t']['_M_impl']['_M_node_count']
205 self.node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left']
212 return int (self.size)
215 if self.count == self.size:
218 self.count = self.count + 1
219 if self.count < self.size:
220 # Compute the next node.
222 if node.dereference()['_M_right']:
223 node = node.dereference()['_M_right']
224 while node.dereference()['_M_left']:
225 node = node.dereference()['_M_left']
227 parent = node.dereference()['_M_parent']
228 while node == parent.dereference()['_M_right']:
230 parent = parent.dereference()['_M_parent']
231 if node.dereference()['_M_right'] != parent:
236 # This is a pretty printer for std::_Rb_tree_iterator (which is
237 # std::map::iterator), and has nothing to do with the RbtreeIterator
239 class StdRbtreeIteratorPrinter:
240 "Print std::map::iterator"
242 def __init__ (self, val):
245 def to_string (self):
246 valuetype = self.val.type.template_argument(0)
247 nodetype = gdb.lookup_type('std::_Rb_tree_node < %s >' % valuetype)
248 nodetype = nodetype.pointer()
249 return self.val.cast(nodetype).dereference()['_M_value_field']
253 "Print a std::map or std::multimap"
255 # Turn an RbtreeIterator into a pretty-print iterator.
257 def __init__(self, rbiter, type):
266 if self.count % 2 == 0:
267 n = self.rbiter.next()
268 n = n.cast(self.type).dereference()['_M_value_field']
272 item = self.pair['second']
273 result = ('[%d]' % self.count, item)
274 self.count = self.count + 1
277 def __init__ (self, typename, val):
278 self.typename = typename
280 self.iter = RbtreeIterator (val)
282 def to_string (self):
283 return '%s with %d elements' % (self.typename, len (self.iter))
286 keytype = self.val.type.template_argument(0).const()
287 valuetype = self.val.type.template_argument(1)
288 nodetype = gdb.lookup_type('std::_Rb_tree_node< std::pair< %s, %s > >' % (keytype, valuetype))
289 nodetype = nodetype.pointer()
290 return self._iter (self.iter, nodetype)
292 def display_hint (self):
296 "Print a std::set or std::multiset"
298 # Turn an RbtreeIterator into a pretty-print iterator.
300 def __init__(self, rbiter, type):
309 item = self.rbiter.next()
310 item = item.cast(self.type).dereference()['_M_value_field']
311 # FIXME: this is weird ... what to do?
312 # Maybe a 'set' display hint?
313 result = ('[%d]' % self.count, item)
314 self.count = self.count + 1
317 def __init__ (self, typename, val):
318 self.typename = typename
320 self.iter = RbtreeIterator (val)
322 def to_string (self):
323 return '%s with %d elements' % (self.typename, len (self.iter))
326 keytype = self.val.type.template_argument(0)
327 nodetype = gdb.lookup_type('std::_Rb_tree_node< %s >' % keytype).pointer()
328 return self._iter (self.iter, nodetype)
330 class StdBitsetPrinter:
331 "Print a std::bitset"
333 def __init__(self, val):
336 def to_string (self):
337 # If template_argument handled values, we could print the
338 # size. Or we could use a regexp on the type.
342 words = self.val['_M_w']
345 # The _M_w member can be either an unsigned long, or an
346 # array. This depends on the template specialization used.
347 # If it is a single long, convert to a single element list.
348 if wtype.code == gdb.TYPE_CODE_ARRAY:
349 tsize = wtype.target ().sizeof
354 nwords = wtype.sizeof / tsize
362 # Another spot where we could use 'set'?
363 result.append(('[%d]' % (byte * tsize * 8 + bit), 1))
369 class StdDequePrinter:
373 def __init__(self, node, start, end, last, buffer_size):
378 self.buffer_size = buffer_size
385 if self.p == self.last:
388 result = ('[%d]' % self.count, self.p.dereference())
389 self.count = self.count + 1
391 # Advance the 'cur' pointer.
393 if self.p == self.end:
394 # If we got to the end of this bucket, move to the
396 self.node = self.node + 1
397 self.p = self.node[0]
398 self.end = self.p + self.buffer_size
402 def __init__(self, val):
404 self.elttype = val.type.template_argument(0)
405 size = self.elttype.sizeof
407 self.buffer_size = int (512 / size)
412 start = self.val['_M_impl']['_M_start']
413 end = self.val['_M_impl']['_M_finish']
415 delta_n = end['_M_node'] - start['_M_node'] - 1
416 delta_s = start['_M_last'] - start['_M_cur']
417 delta_e = end['_M_cur'] - end['_M_first']
419 size = self.buffer_size * delta_n + delta_s + delta_e
421 return 'std::deque with %d elements' % long (size)
424 start = self.val['_M_impl']['_M_start']
425 end = self.val['_M_impl']['_M_finish']
426 return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'],
427 end['_M_cur'], self.buffer_size)
429 def display_hint (self):
432 class StdDequeIteratorPrinter:
433 "Print std::deque::iterator"
435 def __init__(self, val):
439 return self.val['_M_cur'].dereference()
441 class StdStringPrinter:
442 "Print a std::basic_string of some kind"
444 def __init__(self, encoding, val):
445 self.encoding = encoding
449 # Look up the target encoding as late as possible.
450 encoding = self.encoding
452 encoding = gdb.parameter('target-charset')
454 encoding = gdb.parameter('target-wide-charset')
455 elif isinstance(encoding, WideEncoding):
456 encoding = encoding.value
457 return self.val['_M_dataplus']['_M_p'].string(encoding)
459 def display_hint (self):
462 class Tr1HashtableIterator:
463 def __init__ (self, hash):
465 self.n_buckets = hash['_M_element_count']
466 if self.n_buckets == 0:
469 self.bucket = hash['_M_buckets']
470 self.node = self.bucket[0]
477 # If we advanced off the end of the chain, move to the next
479 while self.node == 0:
480 self.bucket = self.bucket + 1
481 self.node = self.bucket[0]
483 # If we advanced off the end of the bucket array, then
485 if self.count == self.n_buckets:
488 self.count = self.count + 1
493 result = self.node.dereference()['_M_v']
494 self.node = self.node.dereference()['_M_next']
498 class Tr1UnorderedSetPrinter:
499 "Print a tr1::unordered_set"
501 def __init__ (self, typename, val):
502 self.typename = typename
505 def to_string (self):
506 return '%s with %d elements' % (self.typename, self.val['_M_element_count'])
509 def format_count (i):
513 counter = itertools.imap (self.format_count, itertools.count())
514 return itertools.izip (counter, Tr1HashtableIterator (self.val))
516 class Tr1UnorderedMapPrinter:
517 "Print a tr1::unordered_map"
519 def __init__ (self, typename, val):
520 self.typename = typename
523 def to_string (self):
524 return '%s with %d elements' % (self.typename, self.val['_M_element_count'])
533 def format_one (elt):
534 return (elt['first'], elt['second'])
537 def format_count (i):
541 counter = itertools.imap (self.format_count, itertools.count())
542 # Map over the hash table and flatten the result.
543 data = self.flatten (itertools.imap (self.format_one, Tr1HashtableIterator (self.val)))
544 # Zip the two iterators together.
545 return itertools.izip (counter, data)
547 def display_hint (self):
550 def register_libstdcxx_printers (obj):
551 "Register libstdc++ pretty-printers with objfile Obj."
556 obj.pretty_printers.append (lookup_function)
558 def lookup_function (val):
559 "Look-up and return a pretty-printer that can print val."
564 # If it points to a reference, get the reference.
565 if type.code == gdb.TYPE_CODE_REF:
566 type = type.target ()
568 # Get the unqualified type, stripped of typedefs.
569 type = type.unqualified ().strip_typedefs ()
576 # Iterate over local dictionary of types to determine
577 # if a printer is registered for that type. Return an
578 # instantiation of the printer if found.
579 for function in pretty_printers_dict:
580 if function.search (typename):
581 return pretty_printers_dict[function] (val)
583 # Cannot find a pretty printer. Return None.
586 def build_libstdcxx_dictionary ():
587 # libstdc++ objects requiring pretty-printing.
589 # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html
590 pretty_printers_dict[re.compile('^std::basic_string<char,.*>$')] = lambda val: StdStringPrinter(0, val)
591 pretty_printers_dict[re.compile('^std::basic_string<wchar_t,.*>$')] = lambda val: StdStringPrinter(1, val)
592 pretty_printers_dict[re.compile('^std::basic_string<char16_t,.*>$')] = lambda val: StdStringPrinter('UTF-16', val)
593 pretty_printers_dict[re.compile('^std::basic_string<char32_t,.*>$')] = lambda val: StdStringPrinter('UTF-32', val)
594 pretty_printers_dict[re.compile('^std::bitset<.*>$')] = StdBitsetPrinter
595 pretty_printers_dict[re.compile('^std::deque<.*>$')] = StdDequePrinter
596 pretty_printers_dict[re.compile('^std::list<.*>$')] = StdListPrinter
597 pretty_printers_dict[re.compile('^std::map<.*>$')] = lambda val: StdMapPrinter("std::map", val)
598 pretty_printers_dict[re.compile('^std::multimap<.*>$')] = lambda val: StdMapPrinter("std::multimap", val)
599 pretty_printers_dict[re.compile('^std::multiset<.*>$')] = lambda val: StdSetPrinter("std::multiset", val)
600 pretty_printers_dict[re.compile('^std::priority_queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::priority_queue", val)
601 pretty_printers_dict[re.compile('^std::queue<.*>$')] = lambda val: StdStackOrQueuePrinter("std::queue", val)
602 pretty_printers_dict[re.compile('^std::set<.*>$')] = lambda val: StdSetPrinter("std::set", val)
603 pretty_printers_dict[re.compile('^std::stack<.*>$')] = lambda val: StdStackOrQueuePrinter("std::stack", val)
604 pretty_printers_dict[re.compile('^std::unique_ptr<.*>$')] = UniquePointerPrinter
605 pretty_printers_dict[re.compile('^std::vector<.*>$')] = StdVectorPrinter
608 # These are the TR1 and C++0x printers.
609 # For array - the default GDB pretty-printer seems reasonable.
610 pretty_printers_dict[re.compile('^std::shared_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::shared_ptr', val)
611 pretty_printers_dict[re.compile('^std::weak_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::weak_ptr', val)
612 pretty_printers_dict[re.compile('^std::unordered_map<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::unordered_map', val)
613 pretty_printers_dict[re.compile('^std::unordered_set<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::unordered_set', val)
614 pretty_printers_dict[re.compile('^std::unordered_multimap<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::unordered_multimap', val)
615 pretty_printers_dict[re.compile('^std::unordered_multiset<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::unordered_multiset', val)
617 pretty_printers_dict[re.compile('^std::tr1::shared_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::tr1::shared_ptr', val)
618 pretty_printers_dict[re.compile('^std::tr1::weak_ptr<.*>$')] = lambda val: StdPointerPrinter ('std::tr1::weak_ptr', val)
619 pretty_printers_dict[re.compile('^std::tr1::unordered_map<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_map', val)
620 pretty_printers_dict[re.compile('^std::tr1::unordered_set<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_set', val)
621 pretty_printers_dict[re.compile('^std::tr1::unordered_multimap<.*>$')] = lambda val: Tr1UnorderedMapPrinter ('std::tr1::unordered_multimap', val)
622 pretty_printers_dict[re.compile('^std::tr1::unordered_multiset<.*>$')] = lambda val: Tr1UnorderedSetPrinter ('std::tr1::unordered_multiset', val)
626 pretty_printers_dict[re.compile('^__gnu_cxx::slist<.*>$')] = StdSlistPrinter
629 # These shouldn't be necessary, if GDB "print *i" worked.
630 # But it often doesn't, so here they are.
631 pretty_printers_dict[re.compile('^std::_List_iterator<.*>$')] = lambda val: StdListIteratorPrinter(val)
632 pretty_printers_dict[re.compile('^std::_List_const_iterator<.*>$')] = lambda val: StdListIteratorPrinter(val)
633 pretty_printers_dict[re.compile('^std::_Rb_tree_iterator<.*>$')] = lambda val: StdRbtreeIteratorPrinter(val)
634 pretty_printers_dict[re.compile('^std::_Rb_tree_const_iterator<.*>$')] = lambda val: StdRbtreeIteratorPrinter(val)
635 pretty_printers_dict[re.compile('^std::_Deque_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val)
636 pretty_printers_dict[re.compile('^std::_Deque_const_iterator<.*>$')] = lambda val: StdDequeIteratorPrinter(val)
637 pretty_printers_dict[re.compile('^__gnu_cxx::__normal_iterator<.*>$')] = lambda val: StdVectorIteratorPrinter(val)
638 pretty_printers_dict[re.compile('^__gnu_cxx::_Slist_iterator<.*>$')] = lambda val: StdSlistIteratorPrinter(val)
640 pretty_printers_dict = {}
642 build_libstdcxx_dictionary ()