]>
Commit | Line | Data |
---|---|---|
41850419 TT |
1 | # Pretty-printers for libstc++. |
2 | ||
3efe2bf7 | 3 | # Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. |
41850419 TT |
4 | |
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. | |
9 | # | |
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. | |
14 | # | |
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/>. | |
17 | ||
d1f736a2 | 18 | import gdb |
41850419 TT |
19 | import itertools |
20 | import re | |
21 | ||
d63c53cc TT |
22 | # Try to use the new-style pretty-printing if available. |
23 | _use_gdb_pp = True | |
24 | try: | |
25 | import gdb.printing | |
26 | except ImportError: | |
27 | _use_gdb_pp = False | |
28 | ||
3efe2bf7 TT |
29 | # Starting with the type ORIG, search for the member type NAME. This |
30 | # handles searching upward through superclasses. This is needed to | |
31 | # work around http://sourceware.org/bugzilla/show_bug.cgi?id=13615. | |
32 | def find_type(orig, name): | |
33 | typ = orig.strip_typedefs() | |
34 | while True: | |
35 | search = str(typ) + '::' + name | |
36 | try: | |
37 | return gdb.lookup_type(search) | |
38 | except RuntimeError: | |
39 | pass | |
40 | # The type was not found, so try the superclass. We only need | |
41 | # to check the first superclass, so we don't bother with | |
42 | # anything fancier here. | |
43 | field = typ.fields()[0] | |
44 | if not field.is_base_class: | |
45 | raise ValueError, "Cannot find type %s::%s" % (str(orig), name) | |
46 | typ = field.type | |
47 | ||
a1527f2f JW |
48 | class SharedPointerPrinter: |
49 | "Print a shared_ptr or weak_ptr" | |
41850419 TT |
50 | |
51 | def __init__ (self, typename, val): | |
52 | self.typename = typename | |
53 | self.val = val | |
54 | ||
55 | def to_string (self): | |
a1527f2f JW |
56 | state = 'empty' |
57 | refcounts = self.val['_M_refcount']['_M_pi'] | |
58 | if refcounts != 0: | |
59 | usecount = refcounts['_M_use_count'] | |
60 | weakcount = refcounts['_M_weak_count'] | |
61 | if usecount == 0: | |
62 | state = 'expired, weak %d' % weakcount | |
63 | else: | |
64 | state = 'count %d, weak %d' % (usecount, weakcount - 1) | |
65 | return '%s (%s) %s' % (self.typename, state, self.val['_M_ptr']) | |
41850419 TT |
66 | |
67 | class UniquePointerPrinter: | |
68 | "Print a unique_ptr" | |
69 | ||
d63c53cc | 70 | def __init__ (self, typename, val): |
41850419 TT |
71 | self.val = val |
72 | ||
73 | def to_string (self): | |
74 | return self.val['_M_t'] | |
75 | ||
76 | class StdListPrinter: | |
77 | "Print a std::list" | |
78 | ||
79 | class _iterator: | |
80 | def __init__(self, nodetype, head): | |
81 | self.nodetype = nodetype | |
82 | self.base = head['_M_next'] | |
83 | self.head = head.address | |
84 | self.count = 0 | |
85 | ||
86 | def __iter__(self): | |
87 | return self | |
88 | ||
89 | def next(self): | |
90 | if self.base == self.head: | |
91 | raise StopIteration | |
92 | elt = self.base.cast(self.nodetype).dereference() | |
93 | self.base = elt['_M_next'] | |
94 | count = self.count | |
95 | self.count = self.count + 1 | |
96 | return ('[%d]' % count, elt['_M_data']) | |
97 | ||
cd0961a5 PM |
98 | def __init__(self, typename, val): |
99 | self.typename = typename | |
41850419 TT |
100 | self.val = val |
101 | ||
102 | def children(self): | |
3efe2bf7 TT |
103 | nodetype = find_type(self.val.type, '_Node') |
104 | nodetype = nodetype.strip_typedefs().pointer() | |
41850419 TT |
105 | return self._iterator(nodetype, self.val['_M_impl']['_M_node']) |
106 | ||
107 | def to_string(self): | |
108 | if self.val['_M_impl']['_M_node'].address == self.val['_M_impl']['_M_node']['_M_next']: | |
cd0961a5 PM |
109 | return 'empty %s' % (self.typename) |
110 | return '%s' % (self.typename) | |
41850419 TT |
111 | |
112 | class StdListIteratorPrinter: | |
113 | "Print std::list::iterator" | |
114 | ||
cd0961a5 | 115 | def __init__(self, typename, val): |
41850419 | 116 | self.val = val |
cd0961a5 | 117 | self.typename = typename |
41850419 TT |
118 | |
119 | def to_string(self): | |
3efe2bf7 TT |
120 | nodetype = find_type(self.val.type, '_Node') |
121 | nodetype = nodetype.strip_typedefs().pointer() | |
41850419 TT |
122 | return self.val['_M_node'].cast(nodetype).dereference()['_M_data'] |
123 | ||
124 | class StdSlistPrinter: | |
125 | "Print a __gnu_cxx::slist" | |
126 | ||
127 | class _iterator: | |
128 | def __init__(self, nodetype, head): | |
129 | self.nodetype = nodetype | |
130 | self.base = head['_M_head']['_M_next'] | |
131 | self.count = 0 | |
132 | ||
133 | def __iter__(self): | |
134 | return self | |
135 | ||
136 | def next(self): | |
137 | if self.base == 0: | |
138 | raise StopIteration | |
139 | elt = self.base.cast(self.nodetype).dereference() | |
140 | self.base = elt['_M_next'] | |
141 | count = self.count | |
142 | self.count = self.count + 1 | |
143 | return ('[%d]' % count, elt['_M_data']) | |
144 | ||
d63c53cc | 145 | def __init__(self, typename, val): |
41850419 TT |
146 | self.val = val |
147 | ||
148 | def children(self): | |
3efe2bf7 TT |
149 | nodetype = find_type(self.val.type, '_Node') |
150 | nodetype = nodetype.strip_typedefs().pointer() | |
41850419 TT |
151 | return self._iterator(nodetype, self.val) |
152 | ||
153 | def to_string(self): | |
154 | if self.val['_M_head']['_M_next'] == 0: | |
155 | return 'empty __gnu_cxx::slist' | |
156 | return '__gnu_cxx::slist' | |
157 | ||
158 | class StdSlistIteratorPrinter: | |
159 | "Print __gnu_cxx::slist::iterator" | |
160 | ||
d63c53cc | 161 | def __init__(self, typename, val): |
41850419 TT |
162 | self.val = val |
163 | ||
164 | def to_string(self): | |
3efe2bf7 TT |
165 | nodetype = find_type(self.val.type, '_Node') |
166 | nodetype = nodetype.strip_typedefs().pointer() | |
41850419 TT |
167 | return self.val['_M_node'].cast(nodetype).dereference()['_M_data'] |
168 | ||
169 | class StdVectorPrinter: | |
170 | "Print a std::vector" | |
171 | ||
172 | class _iterator: | |
7bf7b578 CM |
173 | def __init__ (self, start, finish, bitvec): |
174 | self.bitvec = bitvec | |
175 | if bitvec: | |
176 | self.item = start['_M_p'] | |
177 | self.so = start['_M_offset'] | |
178 | self.finish = finish['_M_p'] | |
179 | self.fo = finish['_M_offset'] | |
180 | itype = self.item.dereference().type | |
181 | self.isize = 8 * itype.sizeof | |
182 | else: | |
183 | self.item = start | |
184 | self.finish = finish | |
41850419 TT |
185 | self.count = 0 |
186 | ||
187 | def __iter__(self): | |
188 | return self | |
189 | ||
190 | def next(self): | |
41850419 TT |
191 | count = self.count |
192 | self.count = self.count + 1 | |
7bf7b578 CM |
193 | if self.bitvec: |
194 | if self.item == self.finish and self.so >= self.fo: | |
195 | raise StopIteration | |
196 | elt = self.item.dereference() | |
db4e59bb JW |
197 | if elt & (1 << self.so): |
198 | obit = 1 | |
199 | else: | |
200 | obit = 0 | |
7bf7b578 CM |
201 | self.so = self.so + 1 |
202 | if self.so >= self.isize: | |
203 | self.item = self.item + 1 | |
204 | self.so = 0 | |
205 | return ('[%d]' % count, obit) | |
206 | else: | |
207 | if self.item == self.finish: | |
208 | raise StopIteration | |
209 | elt = self.item.dereference() | |
210 | self.item = self.item + 1 | |
211 | return ('[%d]' % count, elt) | |
41850419 | 212 | |
cd0961a5 PM |
213 | def __init__(self, typename, val): |
214 | self.typename = typename | |
41850419 | 215 | self.val = val |
7bf7b578 | 216 | self.is_bool = val.type.template_argument(0).code == gdb.TYPE_CODE_BOOL |
41850419 TT |
217 | |
218 | def children(self): | |
219 | return self._iterator(self.val['_M_impl']['_M_start'], | |
7bf7b578 CM |
220 | self.val['_M_impl']['_M_finish'], |
221 | self.is_bool) | |
41850419 TT |
222 | |
223 | def to_string(self): | |
224 | start = self.val['_M_impl']['_M_start'] | |
225 | finish = self.val['_M_impl']['_M_finish'] | |
226 | end = self.val['_M_impl']['_M_end_of_storage'] | |
7bf7b578 CM |
227 | if self.is_bool: |
228 | start = self.val['_M_impl']['_M_start']['_M_p'] | |
229 | so = self.val['_M_impl']['_M_start']['_M_offset'] | |
230 | finish = self.val['_M_impl']['_M_finish']['_M_p'] | |
231 | fo = self.val['_M_impl']['_M_finish']['_M_offset'] | |
232 | itype = start.dereference().type | |
233 | bl = 8 * itype.sizeof | |
234 | length = (bl - so) + bl * ((finish - start) - 1) + fo | |
235 | capacity = bl * (end - start) | |
236 | return ('%s<bool> of length %d, capacity %d' | |
237 | % (self.typename, int (length), int (capacity))) | |
238 | else: | |
239 | return ('%s of length %d, capacity %d' | |
240 | % (self.typename, int (finish - start), int (end - start))) | |
41850419 TT |
241 | |
242 | def display_hint(self): | |
243 | return 'array' | |
244 | ||
245 | class StdVectorIteratorPrinter: | |
246 | "Print std::vector::iterator" | |
247 | ||
d63c53cc | 248 | def __init__(self, typename, val): |
41850419 TT |
249 | self.val = val |
250 | ||
251 | def to_string(self): | |
252 | return self.val['_M_current'].dereference() | |
253 | ||
8345c8e4 PM |
254 | class StdTuplePrinter: |
255 | "Print a std::tuple" | |
256 | ||
257 | class _iterator: | |
258 | def __init__ (self, head): | |
259 | self.head = head | |
260 | ||
261 | # Set the base class as the initial head of the | |
262 | # tuple. | |
263 | nodes = self.head.type.fields () | |
9dacb44b JW |
264 | if len (nodes) == 1: |
265 | # Set the actual head to the first pair. | |
266 | self.head = self.head.cast (nodes[0].type) | |
267 | elif len (nodes) != 0: | |
b2e894b5 | 268 | raise ValueError, "Top of tuple tree does not consist of a single node." |
8345c8e4 PM |
269 | self.count = 0 |
270 | ||
271 | def __iter__ (self): | |
272 | return self | |
273 | ||
274 | def next (self): | |
275 | nodes = self.head.type.fields () | |
276 | # Check for further recursions in the inheritance tree. | |
277 | if len (nodes) == 0: | |
278 | raise StopIteration | |
279 | # Check that this iteration has an expected structure. | |
280 | if len (nodes) != 2: | |
b2e894b5 | 281 | raise ValueError, "Cannot parse more than 2 nodes in a tuple tree." |
8345c8e4 PM |
282 | |
283 | # - Left node is the next recursion parent. | |
284 | # - Right node is the actual class contained in the tuple. | |
285 | ||
286 | # Process right node. | |
287 | impl = self.head.cast (nodes[1].type) | |
288 | ||
289 | # Process left node and set it as head. | |
290 | self.head = self.head.cast (nodes[0].type) | |
291 | self.count = self.count + 1 | |
292 | ||
293 | # Finally, check the implementation. If it is | |
294 | # wrapped in _M_head_impl return that, otherwise return | |
295 | # the value "as is". | |
296 | fields = impl.type.fields () | |
297 | if len (fields) < 1 or fields[0].name != "_M_head_impl": | |
298 | return ('[%d]' % self.count, impl) | |
299 | else: | |
300 | return ('[%d]' % self.count, impl['_M_head_impl']) | |
301 | ||
302 | def __init__ (self, typename, val): | |
303 | self.typename = typename | |
304 | self.val = val; | |
305 | ||
306 | def children (self): | |
307 | return self._iterator (self.val) | |
308 | ||
309 | def to_string (self): | |
9dacb44b JW |
310 | if len (self.val.type.fields ()) == 0: |
311 | return 'empty %s' % (self.typename) | |
8345c8e4 PM |
312 | return '%s containing' % (self.typename) |
313 | ||
41850419 TT |
314 | class StdStackOrQueuePrinter: |
315 | "Print a std::stack or std::queue" | |
316 | ||
317 | def __init__ (self, typename, val): | |
318 | self.typename = typename | |
319 | self.visualizer = gdb.default_visualizer(val['c']) | |
320 | ||
321 | def children (self): | |
322 | return self.visualizer.children() | |
323 | ||
324 | def to_string (self): | |
325 | return '%s wrapping: %s' % (self.typename, | |
326 | self.visualizer.to_string()) | |
327 | ||
328 | def display_hint (self): | |
329 | if hasattr (self.visualizer, 'display_hint'): | |
330 | return self.visualizer.display_hint () | |
331 | return None | |
332 | ||
333 | class RbtreeIterator: | |
334 | def __init__(self, rbtree): | |
335 | self.size = rbtree['_M_t']['_M_impl']['_M_node_count'] | |
336 | self.node = rbtree['_M_t']['_M_impl']['_M_header']['_M_left'] | |
337 | self.count = 0 | |
338 | ||
339 | def __iter__(self): | |
340 | return self | |
341 | ||
342 | def __len__(self): | |
343 | return int (self.size) | |
344 | ||
345 | def next(self): | |
346 | if self.count == self.size: | |
347 | raise StopIteration | |
348 | result = self.node | |
349 | self.count = self.count + 1 | |
350 | if self.count < self.size: | |
351 | # Compute the next node. | |
352 | node = self.node | |
353 | if node.dereference()['_M_right']: | |
354 | node = node.dereference()['_M_right'] | |
355 | while node.dereference()['_M_left']: | |
356 | node = node.dereference()['_M_left'] | |
357 | else: | |
358 | parent = node.dereference()['_M_parent'] | |
359 | while node == parent.dereference()['_M_right']: | |
360 | node = parent | |
361 | parent = parent.dereference()['_M_parent'] | |
362 | if node.dereference()['_M_right'] != parent: | |
363 | node = parent | |
364 | self.node = node | |
365 | return result | |
366 | ||
367 | # This is a pretty printer for std::_Rb_tree_iterator (which is | |
368 | # std::map::iterator), and has nothing to do with the RbtreeIterator | |
369 | # class above. | |
370 | class StdRbtreeIteratorPrinter: | |
371 | "Print std::map::iterator" | |
372 | ||
d63c53cc | 373 | def __init__ (self, typename, val): |
41850419 TT |
374 | self.val = val |
375 | ||
376 | def to_string (self): | |
3efe2bf7 TT |
377 | typename = str(self.val.type.strip_typedefs()) + '::_Link_type' |
378 | nodetype = gdb.lookup_type(typename).strip_typedefs() | |
41850419 TT |
379 | return self.val.cast(nodetype).dereference()['_M_value_field'] |
380 | ||
cd0961a5 PM |
381 | class StdDebugIteratorPrinter: |
382 | "Print a debug enabled version of an iterator" | |
383 | ||
d63c53cc | 384 | def __init__ (self, typename, val): |
cd0961a5 PM |
385 | self.val = val |
386 | ||
387 | # Just strip away the encapsulating __gnu_debug::_Safe_iterator | |
388 | # and return the wrapped iterator value. | |
389 | def to_string (self): | |
390 | itype = self.val.type.template_argument(0) | |
391 | return self.val['_M_current'].cast(itype) | |
41850419 TT |
392 | |
393 | class StdMapPrinter: | |
394 | "Print a std::map or std::multimap" | |
395 | ||
396 | # Turn an RbtreeIterator into a pretty-print iterator. | |
397 | class _iter: | |
398 | def __init__(self, rbiter, type): | |
399 | self.rbiter = rbiter | |
400 | self.count = 0 | |
401 | self.type = type | |
402 | ||
403 | def __iter__(self): | |
404 | return self | |
405 | ||
406 | def next(self): | |
407 | if self.count % 2 == 0: | |
408 | n = self.rbiter.next() | |
409 | n = n.cast(self.type).dereference()['_M_value_field'] | |
410 | self.pair = n | |
411 | item = n['first'] | |
412 | else: | |
413 | item = self.pair['second'] | |
414 | result = ('[%d]' % self.count, item) | |
415 | self.count = self.count + 1 | |
416 | return result | |
417 | ||
418 | def __init__ (self, typename, val): | |
419 | self.typename = typename | |
420 | self.val = val | |
41850419 TT |
421 | |
422 | def to_string (self): | |
ee47095b TT |
423 | return '%s with %d elements' % (self.typename, |
424 | len (RbtreeIterator (self.val))) | |
41850419 TT |
425 | |
426 | def children (self): | |
3efe2bf7 TT |
427 | rep_type = find_type(self.val.type, '_Rep_type') |
428 | node = find_type(rep_type, '_Link_type') | |
429 | node = node.strip_typedefs() | |
430 | return self._iter (RbtreeIterator (self.val), node) | |
41850419 TT |
431 | |
432 | def display_hint (self): | |
433 | return 'map' | |
434 | ||
435 | class StdSetPrinter: | |
436 | "Print a std::set or std::multiset" | |
437 | ||
438 | # Turn an RbtreeIterator into a pretty-print iterator. | |
439 | class _iter: | |
440 | def __init__(self, rbiter, type): | |
441 | self.rbiter = rbiter | |
442 | self.count = 0 | |
443 | self.type = type | |
444 | ||
445 | def __iter__(self): | |
446 | return self | |
447 | ||
448 | def next(self): | |
449 | item = self.rbiter.next() | |
450 | item = item.cast(self.type).dereference()['_M_value_field'] | |
451 | # FIXME: this is weird ... what to do? | |
452 | # Maybe a 'set' display hint? | |
453 | result = ('[%d]' % self.count, item) | |
454 | self.count = self.count + 1 | |
455 | return result | |
456 | ||
457 | def __init__ (self, typename, val): | |
458 | self.typename = typename | |
459 | self.val = val | |
41850419 TT |
460 | |
461 | def to_string (self): | |
ee47095b TT |
462 | return '%s with %d elements' % (self.typename, |
463 | len (RbtreeIterator (self.val))) | |
41850419 TT |
464 | |
465 | def children (self): | |
3efe2bf7 TT |
466 | rep_type = find_type(self.val.type, '_Rep_type') |
467 | node = find_type(rep_type, '_Link_type') | |
468 | node = node.strip_typedefs() | |
469 | return self._iter (RbtreeIterator (self.val), node) | |
41850419 TT |
470 | |
471 | class StdBitsetPrinter: | |
472 | "Print a std::bitset" | |
473 | ||
cd0961a5 PM |
474 | def __init__(self, typename, val): |
475 | self.typename = typename | |
41850419 TT |
476 | self.val = val |
477 | ||
478 | def to_string (self): | |
479 | # If template_argument handled values, we could print the | |
480 | # size. Or we could use a regexp on the type. | |
cd0961a5 | 481 | return '%s' % (self.typename) |
41850419 TT |
482 | |
483 | def children (self): | |
484 | words = self.val['_M_w'] | |
485 | wtype = words.type | |
486 | ||
487 | # The _M_w member can be either an unsigned long, or an | |
488 | # array. This depends on the template specialization used. | |
489 | # If it is a single long, convert to a single element list. | |
490 | if wtype.code == gdb.TYPE_CODE_ARRAY: | |
491 | tsize = wtype.target ().sizeof | |
492 | else: | |
493 | words = [words] | |
494 | tsize = wtype.sizeof | |
495 | ||
496 | nwords = wtype.sizeof / tsize | |
497 | result = [] | |
498 | byte = 0 | |
499 | while byte < nwords: | |
500 | w = words[byte] | |
501 | bit = 0 | |
502 | while w != 0: | |
503 | if (w & 1) != 0: | |
504 | # Another spot where we could use 'set'? | |
505 | result.append(('[%d]' % (byte * tsize * 8 + bit), 1)) | |
506 | bit = bit + 1 | |
507 | w = w >> 1 | |
508 | byte = byte + 1 | |
509 | return result | |
510 | ||
511 | class StdDequePrinter: | |
512 | "Print a std::deque" | |
513 | ||
514 | class _iter: | |
515 | def __init__(self, node, start, end, last, buffer_size): | |
516 | self.node = node | |
517 | self.p = start | |
518 | self.end = end | |
519 | self.last = last | |
520 | self.buffer_size = buffer_size | |
521 | self.count = 0 | |
522 | ||
523 | def __iter__(self): | |
524 | return self | |
525 | ||
526 | def next(self): | |
527 | if self.p == self.last: | |
528 | raise StopIteration | |
529 | ||
530 | result = ('[%d]' % self.count, self.p.dereference()) | |
531 | self.count = self.count + 1 | |
532 | ||
533 | # Advance the 'cur' pointer. | |
534 | self.p = self.p + 1 | |
535 | if self.p == self.end: | |
536 | # If we got to the end of this bucket, move to the | |
537 | # next bucket. | |
538 | self.node = self.node + 1 | |
539 | self.p = self.node[0] | |
540 | self.end = self.p + self.buffer_size | |
541 | ||
542 | return result | |
543 | ||
cd0961a5 PM |
544 | def __init__(self, typename, val): |
545 | self.typename = typename | |
41850419 TT |
546 | self.val = val |
547 | self.elttype = val.type.template_argument(0) | |
548 | size = self.elttype.sizeof | |
549 | if size < 512: | |
550 | self.buffer_size = int (512 / size) | |
551 | else: | |
552 | self.buffer_size = 1 | |
553 | ||
554 | def to_string(self): | |
555 | start = self.val['_M_impl']['_M_start'] | |
556 | end = self.val['_M_impl']['_M_finish'] | |
557 | ||
558 | delta_n = end['_M_node'] - start['_M_node'] - 1 | |
559 | delta_s = start['_M_last'] - start['_M_cur'] | |
560 | delta_e = end['_M_cur'] - end['_M_first'] | |
561 | ||
562 | size = self.buffer_size * delta_n + delta_s + delta_e | |
563 | ||
cd0961a5 | 564 | return '%s with %d elements' % (self.typename, long (size)) |
41850419 TT |
565 | |
566 | def children(self): | |
567 | start = self.val['_M_impl']['_M_start'] | |
568 | end = self.val['_M_impl']['_M_finish'] | |
569 | return self._iter(start['_M_node'], start['_M_cur'], start['_M_last'], | |
570 | end['_M_cur'], self.buffer_size) | |
571 | ||
572 | def display_hint (self): | |
573 | return 'array' | |
574 | ||
575 | class StdDequeIteratorPrinter: | |
576 | "Print std::deque::iterator" | |
577 | ||
d63c53cc | 578 | def __init__(self, typename, val): |
41850419 TT |
579 | self.val = val |
580 | ||
581 | def to_string(self): | |
582 | return self.val['_M_cur'].dereference() | |
583 | ||
584 | class StdStringPrinter: | |
585 | "Print a std::basic_string of some kind" | |
586 | ||
d63c53cc | 587 | def __init__(self, typename, val): |
41850419 TT |
588 | self.val = val |
589 | ||
590 | def to_string(self): | |
271167f1 PM |
591 | # Make sure &string works, too. |
592 | type = self.val.type | |
593 | if type.code == gdb.TYPE_CODE_REF: | |
594 | type = type.target () | |
595 | ||
596 | # Calculate the length of the string so that to_string returns | |
597 | # the string according to length, not according to first null | |
598 | # encountered. | |
599 | ptr = self.val ['_M_dataplus']['_M_p'] | |
600 | realtype = type.unqualified ().strip_typedefs () | |
601 | reptype = gdb.lookup_type (str (realtype) + '::_Rep').pointer () | |
602 | header = ptr.cast(reptype) - 1 | |
603 | len = header.dereference ()['_M_length'] | |
708f539d JW |
604 | if hasattr(ptr, "lazy_string"): |
605 | return ptr.lazy_string (length = len) | |
606 | return ptr.string (length = len) | |
41850419 TT |
607 | |
608 | def display_hint (self): | |
609 | return 'string' | |
610 | ||
611 | class Tr1HashtableIterator: | |
612 | def __init__ (self, hash): | |
d25b1e3a | 613 | self.node = hash['_M_before_begin']['_M_nxt'] |
4dad8b49 | 614 | self.node_type = find_type(hash.type, '__node_type').pointer() |
41850419 TT |
615 | |
616 | def __iter__ (self): | |
617 | return self | |
618 | ||
41850419 | 619 | def next (self): |
d25b1e3a | 620 | if self.node == 0: |
41850419 | 621 | raise StopIteration |
d25b1e3a TT |
622 | node = self.node.cast(self.node_type) |
623 | result = node.dereference()['_M_v'] | |
624 | self.node = node.dereference()['_M_nxt'] | |
41850419 TT |
625 | return result |
626 | ||
627 | class Tr1UnorderedSetPrinter: | |
628 | "Print a tr1::unordered_set" | |
629 | ||
630 | def __init__ (self, typename, val): | |
631 | self.typename = typename | |
632 | self.val = val | |
633 | ||
634 | def to_string (self): | |
635 | return '%s with %d elements' % (self.typename, self.val['_M_element_count']) | |
636 | ||
637 | @staticmethod | |
638 | def format_count (i): | |
639 | return '[%d]' % i | |
640 | ||
641 | def children (self): | |
642 | counter = itertools.imap (self.format_count, itertools.count()) | |
643 | return itertools.izip (counter, Tr1HashtableIterator (self.val)) | |
644 | ||
645 | class Tr1UnorderedMapPrinter: | |
646 | "Print a tr1::unordered_map" | |
647 | ||
648 | def __init__ (self, typename, val): | |
649 | self.typename = typename | |
650 | self.val = val | |
651 | ||
652 | def to_string (self): | |
653 | return '%s with %d elements' % (self.typename, self.val['_M_element_count']) | |
654 | ||
655 | @staticmethod | |
656 | def flatten (list): | |
657 | for elt in list: | |
658 | for i in elt: | |
659 | yield i | |
660 | ||
661 | @staticmethod | |
662 | def format_one (elt): | |
663 | return (elt['first'], elt['second']) | |
664 | ||
665 | @staticmethod | |
666 | def format_count (i): | |
667 | return '[%d]' % i | |
668 | ||
669 | def children (self): | |
670 | counter = itertools.imap (self.format_count, itertools.count()) | |
671 | # Map over the hash table and flatten the result. | |
672 | data = self.flatten (itertools.imap (self.format_one, Tr1HashtableIterator (self.val))) | |
673 | # Zip the two iterators together. | |
674 | return itertools.izip (counter, data) | |
675 | ||
676 | def display_hint (self): | |
677 | return 'map' | |
678 | ||
8dfb08ab JW |
679 | class StdForwardListPrinter: |
680 | "Print a std::forward_list" | |
681 | ||
682 | class _iterator: | |
683 | def __init__(self, nodetype, head): | |
684 | self.nodetype = nodetype | |
685 | self.base = head['_M_next'] | |
686 | self.count = 0 | |
687 | ||
688 | def __iter__(self): | |
689 | return self | |
690 | ||
691 | def next(self): | |
692 | if self.base == 0: | |
693 | raise StopIteration | |
694 | elt = self.base.cast(self.nodetype).dereference() | |
695 | self.base = elt['_M_next'] | |
696 | count = self.count | |
697 | self.count = self.count + 1 | |
698 | return ('[%d]' % count, elt['_M_value']) | |
699 | ||
700 | def __init__(self, typename, val): | |
701 | self.val = val | |
702 | self.typename = typename | |
703 | ||
704 | def children(self): | |
3efe2bf7 TT |
705 | nodetype = find_type(self.val.type, '_Node') |
706 | nodetype = nodetype.strip_typedefs().pointer() | |
8dfb08ab JW |
707 | return self._iterator(nodetype, self.val['_M_impl']['_M_head']) |
708 | ||
709 | def to_string(self): | |
710 | if self.val['_M_impl']['_M_head']['_M_next'] == 0: | |
711 | return 'empty %s' % (self.typename) | |
712 | return '%s' % (self.typename) | |
713 | ||
714 | ||
d63c53cc TT |
715 | # A "regular expression" printer which conforms to the |
716 | # "SubPrettyPrinter" protocol from gdb.printing. | |
717 | class RxPrinter(object): | |
718 | def __init__(self, name, function): | |
719 | super(RxPrinter, self).__init__() | |
720 | self.name = name | |
721 | self.function = function | |
722 | self.enabled = True | |
723 | ||
724 | def invoke(self, value): | |
725 | if not self.enabled: | |
726 | return None | |
727 | return self.function(self.name, value) | |
728 | ||
729 | # A pretty-printer that conforms to the "PrettyPrinter" protocol from | |
730 | # gdb.printing. It can also be used directly as an old-style printer. | |
731 | class Printer(object): | |
732 | def __init__(self, name): | |
733 | super(Printer, self).__init__() | |
734 | self.name = name | |
735 | self.subprinters = [] | |
736 | self.lookup = {} | |
737 | self.enabled = True | |
738 | self.compiled_rx = re.compile('^([a-zA-Z0-9_:]+)<.*>$') | |
739 | ||
740 | def add(self, name, function): | |
741 | # A small sanity check. | |
742 | # FIXME | |
743 | if not self.compiled_rx.match(name + '<>'): | |
744 | raise ValueError, 'libstdc++ programming error: "%s" does not match' % name | |
745 | printer = RxPrinter(name, function) | |
746 | self.subprinters.append(printer) | |
747 | self.lookup[name] = printer | |
41850419 | 748 | |
3efe2bf7 TT |
749 | # Add a name using _GLIBCXX_BEGIN_NAMESPACE_VERSION. |
750 | def add_version(self, base, name, function): | |
751 | self.add(base + name, function) | |
752 | self.add(base + '__7::' + name, function) | |
753 | ||
754 | # Add a name using _GLIBCXX_BEGIN_NAMESPACE_CONTAINER. | |
755 | def add_container(self, base, name, function): | |
756 | self.add_version(base, name, function) | |
757 | self.add_version(base + '__cxx1998::', name, function) | |
758 | ||
d63c53cc TT |
759 | @staticmethod |
760 | def get_basic_type(type): | |
761 | # If it points to a reference, get the reference. | |
762 | if type.code == gdb.TYPE_CODE_REF: | |
763 | type = type.target () | |
41850419 | 764 | |
d63c53cc TT |
765 | # Get the unqualified type, stripped of typedefs. |
766 | type = type.unqualified ().strip_typedefs () | |
41850419 | 767 | |
d63c53cc | 768 | return type.tag |
41850419 | 769 | |
d63c53cc TT |
770 | def __call__(self, val): |
771 | typename = self.get_basic_type(val.type) | |
772 | if not typename: | |
773 | return None | |
41850419 | 774 | |
d63c53cc TT |
775 | # All the types we match are template types, so we can use a |
776 | # dictionary. | |
777 | match = self.compiled_rx.match(typename) | |
778 | if not match: | |
779 | return None | |
41850419 | 780 | |
d63c53cc TT |
781 | basename = match.group(1) |
782 | if basename in self.lookup: | |
783 | return self.lookup[basename].invoke(val) | |
41850419 | 784 | |
d63c53cc | 785 | # Cannot find a pretty printer. Return None. |
41850419 TT |
786 | return None |
787 | ||
d63c53cc TT |
788 | libstdcxx_printer = None |
789 | ||
790 | def register_libstdcxx_printers (obj): | |
791 | "Register libstdc++ pretty-printers with objfile Obj." | |
792 | ||
793 | global _use_gdb_pp | |
794 | global libstdcxx_printer | |
795 | ||
796 | if _use_gdb_pp: | |
797 | gdb.printing.register_pretty_printer(obj, libstdcxx_printer) | |
798 | else: | |
799 | if obj is None: | |
800 | obj = gdb | |
801 | obj.pretty_printers.append(libstdcxx_printer) | |
41850419 TT |
802 | |
803 | def build_libstdcxx_dictionary (): | |
d63c53cc TT |
804 | global libstdcxx_printer |
805 | ||
806 | libstdcxx_printer = Printer("libstdc++-v6") | |
807 | ||
3efe2bf7 TT |
808 | # For _GLIBCXX_BEGIN_NAMESPACE_VERSION. |
809 | vers = '(__7::)?' | |
810 | # For _GLIBCXX_BEGIN_NAMESPACE_CONTAINER. | |
811 | container = '(__cxx1998::' + vers + ')?' | |
812 | ||
41850419 TT |
813 | # libstdc++ objects requiring pretty-printing. |
814 | # In order from: | |
815 | # http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/a01847.html | |
3efe2bf7 TT |
816 | libstdcxx_printer.add_version('std::', 'basic_string', StdStringPrinter) |
817 | libstdcxx_printer.add_container('std::', 'bitset', StdBitsetPrinter) | |
818 | libstdcxx_printer.add_container('std::', 'deque', StdDequePrinter) | |
819 | libstdcxx_printer.add_container('std::', 'list', StdListPrinter) | |
820 | libstdcxx_printer.add_container('std::', 'map', StdMapPrinter) | |
821 | libstdcxx_printer.add_container('std::', 'multimap', StdMapPrinter) | |
822 | libstdcxx_printer.add_container('std::', 'multiset', StdSetPrinter) | |
823 | libstdcxx_printer.add_version('std::', 'priority_queue', | |
824 | StdStackOrQueuePrinter) | |
825 | libstdcxx_printer.add_version('std::', 'queue', StdStackOrQueuePrinter) | |
826 | libstdcxx_printer.add_version('std::', 'tuple', StdTuplePrinter) | |
827 | libstdcxx_printer.add_container('std::', 'set', StdSetPrinter) | |
828 | libstdcxx_printer.add_version('std::', 'stack', StdStackOrQueuePrinter) | |
829 | libstdcxx_printer.add_version('std::', 'unique_ptr', UniquePointerPrinter) | |
830 | libstdcxx_printer.add_container('std::', 'vector', StdVectorPrinter) | |
41850419 TT |
831 | # vector<bool> |
832 | ||
cd0961a5 | 833 | # Printer registrations for classes compiled with -D_GLIBCXX_DEBUG. |
d63c53cc TT |
834 | libstdcxx_printer.add('std::__debug::bitset', StdBitsetPrinter) |
835 | libstdcxx_printer.add('std::__debug::deque', StdDequePrinter) | |
836 | libstdcxx_printer.add('std::__debug::list', StdListPrinter) | |
837 | libstdcxx_printer.add('std::__debug::map', StdMapPrinter) | |
838 | libstdcxx_printer.add('std::__debug::multimap', StdMapPrinter) | |
839 | libstdcxx_printer.add('std::__debug::multiset', StdSetPrinter) | |
840 | libstdcxx_printer.add('std::__debug::priority_queue', | |
841 | StdStackOrQueuePrinter) | |
842 | libstdcxx_printer.add('std::__debug::queue', StdStackOrQueuePrinter) | |
843 | libstdcxx_printer.add('std::__debug::set', StdSetPrinter) | |
844 | libstdcxx_printer.add('std::__debug::stack', StdStackOrQueuePrinter) | |
845 | libstdcxx_printer.add('std::__debug::unique_ptr', UniquePointerPrinter) | |
846 | libstdcxx_printer.add('std::__debug::vector', StdVectorPrinter) | |
cd0961a5 | 847 | |
41850419 TT |
848 | # These are the TR1 and C++0x printers. |
849 | # For array - the default GDB pretty-printer seems reasonable. | |
a1527f2f JW |
850 | libstdcxx_printer.add_version('std::', 'shared_ptr', SharedPointerPrinter) |
851 | libstdcxx_printer.add_version('std::', 'weak_ptr', SharedPointerPrinter) | |
3efe2bf7 TT |
852 | libstdcxx_printer.add_container('std::', 'unordered_map', |
853 | Tr1UnorderedMapPrinter) | |
854 | libstdcxx_printer.add_container('std::', 'unordered_set', | |
855 | Tr1UnorderedSetPrinter) | |
856 | libstdcxx_printer.add_container('std::', 'unordered_multimap', | |
857 | Tr1UnorderedMapPrinter) | |
858 | libstdcxx_printer.add_container('std::', 'unordered_multiset', | |
859 | Tr1UnorderedSetPrinter) | |
860 | libstdcxx_printer.add_container('std::', 'forward_list', | |
861 | StdForwardListPrinter) | |
862 | ||
a1527f2f JW |
863 | libstdcxx_printer.add_version('std::tr1::', 'shared_ptr', SharedPointerPrinter) |
864 | libstdcxx_printer.add_version('std::tr1::', 'weak_ptr', SharedPointerPrinter) | |
3efe2bf7 TT |
865 | libstdcxx_printer.add_version('std::tr1::', 'unordered_map', |
866 | Tr1UnorderedMapPrinter) | |
867 | libstdcxx_printer.add_version('std::tr1::', 'unordered_set', | |
868 | Tr1UnorderedSetPrinter) | |
869 | libstdcxx_printer.add_version('std::tr1::', 'unordered_multimap', | |
870 | Tr1UnorderedMapPrinter) | |
871 | libstdcxx_printer.add_version('std::tr1::', 'unordered_multiset', | |
872 | Tr1UnorderedSetPrinter) | |
41850419 | 873 | |
cd0961a5 PM |
874 | # These are the C++0x printer registrations for -D_GLIBCXX_DEBUG cases. |
875 | # The tr1 namespace printers do not seem to have any debug | |
876 | # equivalents, so do no register them. | |
d63c53cc TT |
877 | libstdcxx_printer.add('std::__debug::unordered_map', |
878 | Tr1UnorderedMapPrinter) | |
879 | libstdcxx_printer.add('std::__debug::unordered_set', | |
880 | Tr1UnorderedSetPrinter) | |
881 | libstdcxx_printer.add('std::__debug::unordered_multimap', | |
882 | Tr1UnorderedMapPrinter) | |
883 | libstdcxx_printer.add('std::__debug::unordered_multiset', | |
884 | Tr1UnorderedSetPrinter) | |
8dfb08ab JW |
885 | libstdcxx_printer.add('std::__debug::forward_list', |
886 | StdForwardListPrinter) | |
cd0961a5 | 887 | |
41850419 TT |
888 | |
889 | # Extensions. | |
3efe2bf7 | 890 | libstdcxx_printer.add_version('__gnu_cxx::', 'slist', StdSlistPrinter) |
41850419 TT |
891 | |
892 | if True: | |
893 | # These shouldn't be necessary, if GDB "print *i" worked. | |
894 | # But it often doesn't, so here they are. | |
3efe2bf7 TT |
895 | libstdcxx_printer.add_container('std::', '_List_iterator', |
896 | StdListIteratorPrinter) | |
897 | libstdcxx_printer.add_container('std::', '_List_const_iterator', | |
898 | StdListIteratorPrinter) | |
899 | libstdcxx_printer.add_version('std::', '_Rb_tree_iterator', | |
900 | StdRbtreeIteratorPrinter) | |
901 | libstdcxx_printer.add_version('std::', '_Rb_tree_const_iterator', | |
902 | StdRbtreeIteratorPrinter) | |
903 | libstdcxx_printer.add_container('std::', '_Deque_iterator', | |
904 | StdDequeIteratorPrinter) | |
905 | libstdcxx_printer.add_container('std::', '_Deque_const_iterator', | |
906 | StdDequeIteratorPrinter) | |
907 | libstdcxx_printer.add_version('__gnu_cxx::', '__normal_iterator', | |
908 | StdVectorIteratorPrinter) | |
909 | libstdcxx_printer.add_version('__gnu_cxx::', '_Slist_iterator', | |
910 | StdSlistIteratorPrinter) | |
d63c53cc TT |
911 | |
912 | # Debug (compiled with -D_GLIBCXX_DEBUG) printer | |
913 | # registrations. The Rb_tree debug iterator when unwrapped | |
914 | # from the encapsulating __gnu_debug::_Safe_iterator does not | |
915 | # have the __norm namespace. Just use the existing printer | |
916 | # registration for that. | |
917 | libstdcxx_printer.add('__gnu_debug::_Safe_iterator', | |
918 | StdDebugIteratorPrinter) | |
919 | libstdcxx_printer.add('std::__norm::_List_iterator', | |
920 | StdListIteratorPrinter) | |
921 | libstdcxx_printer.add('std::__norm::_List_const_iterator', | |
922 | StdListIteratorPrinter) | |
923 | libstdcxx_printer.add('std::__norm::_Deque_const_iterator', | |
924 | StdDequeIteratorPrinter) | |
925 | libstdcxx_printer.add('std::__norm::_Deque_iterator', | |
926 | StdDequeIteratorPrinter) | |
41850419 TT |
927 | |
928 | build_libstdcxx_dictionary () |