]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - examples/synthetic/libcxx.py
Vendor import of lldb trunk r290819:
[FreeBSD/FreeBSD.git] / examples / synthetic / libcxx.py
1 import lldb
2 import lldb.formatters.Logger
3
4 # libcxx STL formatters for LLDB
5 # These formatters are based upon the implementation of libc++ that
6 # ships with current releases of OS X - They will not work for other implementations
7 # of the standard C++ library - and they are bound to use the
8 # libc++-specific namespace
9
10 # the std::string summary is just an example for your convenience
11 # the actual summary that LLDB uses is C++ code inside the debugger's own core
12
13 # this could probably be made more efficient but since it only reads a handful of bytes at a time
14 # we probably don't need to worry too much about this for the time being
15
16
17 def make_string(F, L):
18     strval = ''
19     G = F.GetData().uint8
20     for X in range(L):
21         V = G[X]
22         if V == 0:
23             break
24         strval = strval + chr(V % 256)
25     return '"' + strval + '"'
26
27 # if we ever care about big-endian, these two functions might need to change
28
29
30 def is_short_string(value):
31     return True if (value & 1) == 0 else False
32
33
34 def extract_short_size(value):
35     return ((value >> 1) % 256)
36
37 # some of the members of libc++ std::string are anonymous or have internal names that convey
38 # no external significance - we access them by index since this saves a name lookup that would add
39 # no information for readers of the code, but when possible try to use
40 # meaningful variable names
41
42
43 def stdstring_SummaryProvider(valobj, dict):
44     logger = lldb.formatters.Logger.Logger()
45     r = valobj.GetChildAtIndex(0)
46     B = r.GetChildAtIndex(0)
47     first = B.GetChildAtIndex(0)
48     D = first.GetChildAtIndex(0)
49     l = D.GetChildAtIndex(0)
50     s = D.GetChildAtIndex(1)
51     D20 = s.GetChildAtIndex(0)
52     size_mode = D20.GetChildAtIndex(0).GetValueAsUnsigned(0)
53     if is_short_string(size_mode):
54         size = extract_short_size(size_mode)
55         return make_string(s.GetChildAtIndex(1), size)
56     else:
57         data_ptr = l.GetChildAtIndex(2)
58         size_vo = l.GetChildAtIndex(1)
59         # the NULL terminator must be accounted for
60         size = size_vo.GetValueAsUnsigned(0) + 1
61         if size <= 1 or size is None:  # should never be the case
62             return '""'
63         try:
64             data = data_ptr.GetPointeeData(0, size)
65         except:
66             return '""'
67         error = lldb.SBError()
68         strval = data.GetString(error, 0)
69         if error.Fail():
70             return '<error:' + error.GetCString() + '>'
71         else:
72             return '"' + strval + '"'
73
74
75 class stdvector_SynthProvider:
76
77     def __init__(self, valobj, dict):
78         logger = lldb.formatters.Logger.Logger()
79         self.valobj = valobj
80
81     def num_children(self):
82         logger = lldb.formatters.Logger.Logger()
83         try:
84             start_val = self.start.GetValueAsUnsigned(0)
85             finish_val = self.finish.GetValueAsUnsigned(0)
86             # Before a vector has been constructed, it will contain bad values
87             # so we really need to be careful about the length we return since
88             # uninitialized data can cause us to return a huge number. We need
89             # to also check for any of the start, finish or end of storage values
90             # being zero (NULL). If any are, then this vector has not been
91             # initialized yet and we should return zero
92
93             # Make sure nothing is NULL
94             if start_val == 0 or finish_val == 0:
95                 return 0
96             # Make sure start is less than finish
97             if start_val >= finish_val:
98                 return 0
99
100             num_children = (finish_val - start_val)
101             if (num_children % self.data_size) != 0:
102                 return 0
103             else:
104                 num_children = num_children / self.data_size
105             return num_children
106         except:
107             return 0
108
109     def get_child_index(self, name):
110         logger = lldb.formatters.Logger.Logger()
111         try:
112             return int(name.lstrip('[').rstrip(']'))
113         except:
114             return -1
115
116     def get_child_at_index(self, index):
117         logger = lldb.formatters.Logger.Logger()
118         logger >> "Retrieving child " + str(index)
119         if index < 0:
120             return None
121         if index >= self.num_children():
122             return None
123         try:
124             offset = index * self.data_size
125             return self.start.CreateChildAtOffset(
126                 '[' + str(index) + ']', offset, self.data_type)
127         except:
128             return None
129
130     def update(self):
131         logger = lldb.formatters.Logger.Logger()
132         try:
133             self.start = self.valobj.GetChildMemberWithName('__begin_')
134             self.finish = self.valobj.GetChildMemberWithName('__end_')
135             # the purpose of this field is unclear, but it is the only field whose type is clearly T* for a vector<T>
136             # if this ends up not being correct, we can use the APIs to get at
137             # template arguments
138             data_type_finder = self.valobj.GetChildMemberWithName(
139                 '__end_cap_').GetChildMemberWithName('__first_')
140             self.data_type = data_type_finder.GetType().GetPointeeType()
141             self.data_size = self.data_type.GetByteSize()
142         except:
143             pass
144
145     def has_children(self):
146         return True
147
148 # Just an example: the actual summary is produced by a summary string:
149 # size=${svar%#}
150
151
152 def stdvector_SummaryProvider(valobj, dict):
153     prov = stdvector_SynthProvider(valobj, None)
154     return 'size=' + str(prov.num_children())
155
156
157 class stdlist_entry:
158
159     def __init__(self, entry):
160         logger = lldb.formatters.Logger.Logger()
161         self.entry = entry
162
163     def _next_impl(self):
164         logger = lldb.formatters.Logger.Logger()
165         return stdlist_entry(self.entry.GetChildMemberWithName('__next_'))
166
167     def _prev_impl(self):
168         logger = lldb.formatters.Logger.Logger()
169         return stdlist_entry(self.entry.GetChildMemberWithName('__prev_'))
170
171     def _value_impl(self):
172         logger = lldb.formatters.Logger.Logger()
173         return self.entry.GetValueAsUnsigned(0)
174
175     def _isnull_impl(self):
176         logger = lldb.formatters.Logger.Logger()
177         return self._value_impl() == 0
178
179     def _sbvalue_impl(self):
180         logger = lldb.formatters.Logger.Logger()
181         return self.entry
182
183     next = property(_next_impl, None)
184     value = property(_value_impl, None)
185     is_null = property(_isnull_impl, None)
186     sbvalue = property(_sbvalue_impl, None)
187
188
189 class stdlist_iterator:
190
191     def increment_node(self, node):
192         logger = lldb.formatters.Logger.Logger()
193         if node.is_null:
194             return None
195         return node.next
196
197     def __init__(self, node):
198         logger = lldb.formatters.Logger.Logger()
199         # we convert the SBValue to an internal node object on entry
200         self.node = stdlist_entry(node)
201
202     def value(self):
203         logger = lldb.formatters.Logger.Logger()
204         return self.node.sbvalue  # and return the SBValue back on exit
205
206     def next(self):
207         logger = lldb.formatters.Logger.Logger()
208         node = self.increment_node(self.node)
209         if node is not None and node.sbvalue.IsValid() and not(node.is_null):
210             self.node = node
211             return self.value()
212         else:
213             return None
214
215     def advance(self, N):
216         logger = lldb.formatters.Logger.Logger()
217         if N < 0:
218             return None
219         if N == 0:
220             return self.value()
221         if N == 1:
222             return self.next()
223         while N > 0:
224             self.next()
225             N = N - 1
226         return self.value()
227
228
229 class stdlist_SynthProvider:
230
231     def __init__(self, valobj, dict):
232         logger = lldb.formatters.Logger.Logger()
233         self.valobj = valobj
234         self.count = None
235
236     def next_node(self, node):
237         logger = lldb.formatters.Logger.Logger()
238         return node.GetChildMemberWithName('__next_')
239
240     def value(self, node):
241         logger = lldb.formatters.Logger.Logger()
242         return node.GetValueAsUnsigned()
243
244     # Floyd's cycle-finding algorithm
245     # try to detect if this list has a loop
246     def has_loop(self):
247         global _list_uses_loop_detector
248         logger = lldb.formatters.Logger.Logger()
249         if not _list_uses_loop_detector:
250             logger >> "Asked not to use loop detection"
251             return False
252         slow = stdlist_entry(self.head)
253         fast1 = stdlist_entry(self.head)
254         fast2 = stdlist_entry(self.head)
255         while slow.next.value != self.node_address:
256             slow_value = slow.value
257             fast1 = fast2.next
258             fast2 = fast1.next
259             if fast1.value == slow_value or fast2.value == slow_value:
260                 return True
261             slow = slow.next
262         return False
263
264     def num_children(self):
265         global _list_capping_size
266         logger = lldb.formatters.Logger.Logger()
267         if self.count is None:
268             self.count = self.num_children_impl()
269             if self.count > _list_capping_size:
270                 self.count = _list_capping_size
271         return self.count
272
273     def num_children_impl(self):
274         global _list_capping_size
275         logger = lldb.formatters.Logger.Logger()
276         try:
277             next_val = self.head.GetValueAsUnsigned(0)
278             prev_val = self.tail.GetValueAsUnsigned(0)
279             # After a std::list has been initialized, both next and prev will
280             # be non-NULL
281             if next_val == 0 or prev_val == 0:
282                 return 0
283             if next_val == self.node_address:
284                 return 0
285             if next_val == prev_val:
286                 return 1
287             if self.has_loop():
288                 return 0
289             size = 2
290             current = stdlist_entry(self.head)
291             while current.next.value != self.node_address:
292                 size = size + 1
293                 current = current.next
294                 if size > _list_capping_size:
295                     return _list_capping_size
296             return (size - 1)
297         except:
298             return 0
299
300     def get_child_index(self, name):
301         logger = lldb.formatters.Logger.Logger()
302         try:
303             return int(name.lstrip('[').rstrip(']'))
304         except:
305             return -1
306
307     def get_child_at_index(self, index):
308         logger = lldb.formatters.Logger.Logger()
309         logger >> "Fetching child " + str(index)
310         if index < 0:
311             return None
312         if index >= self.num_children():
313             return None
314         try:
315             current = stdlist_iterator(self.head)
316             current = current.advance(index)
317             # we do not return __value_ because then all our children would be named __value_
318             # we need to make a copy of __value__ with the right name -
319             # unfortunate
320             obj = current.GetChildMemberWithName('__value_')
321             obj_data = obj.GetData()
322             return self.valobj.CreateValueFromData(
323                 '[' + str(index) + ']', obj_data, self.data_type)
324         except:
325             return None
326
327     def extract_type(self):
328         logger = lldb.formatters.Logger.Logger()
329         list_type = self.valobj.GetType().GetUnqualifiedType()
330         if list_type.IsReferenceType():
331             list_type = list_type.GetDereferencedType()
332         if list_type.GetNumberOfTemplateArguments() > 0:
333             data_type = list_type.GetTemplateArgumentType(0)
334         else:
335             data_type = None
336         return data_type
337
338     def update(self):
339         logger = lldb.formatters.Logger.Logger()
340         self.count = None
341         try:
342             impl = self.valobj.GetChildMemberWithName('__end_')
343             self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0)
344             self.head = impl.GetChildMemberWithName('__next_')
345             self.tail = impl.GetChildMemberWithName('__prev_')
346             self.data_type = self.extract_type()
347             self.data_size = self.data_type.GetByteSize()
348         except:
349             pass
350
351     def has_children(self):
352         return True
353
354
355 # Just an example: the actual summary is produced by a summary string:
356 # size=${svar%#}
357 def stdlist_SummaryProvider(valobj, dict):
358     prov = stdlist_SynthProvider(valobj, None)
359     return 'size=' + str(prov.num_children())
360
361 # a tree node - this class makes the syntax in the actual iterator nicer
362 # to read and maintain
363
364
365 class stdmap_iterator_node:
366
367     def _left_impl(self):
368         logger = lldb.formatters.Logger.Logger()
369         return stdmap_iterator_node(
370             self.node.GetChildMemberWithName("__left_"))
371
372     def _right_impl(self):
373         logger = lldb.formatters.Logger.Logger()
374         return stdmap_iterator_node(
375             self.node.GetChildMemberWithName("__right_"))
376
377     def _parent_impl(self):
378         logger = lldb.formatters.Logger.Logger()
379         return stdmap_iterator_node(
380             self.node.GetChildMemberWithName("__parent_"))
381
382     def _value_impl(self):
383         logger = lldb.formatters.Logger.Logger()
384         return self.node.GetValueAsUnsigned(0)
385
386     def _sbvalue_impl(self):
387         logger = lldb.formatters.Logger.Logger()
388         return self.node
389
390     def _null_impl(self):
391         logger = lldb.formatters.Logger.Logger()
392         return self.value == 0
393
394     def __init__(self, node):
395         logger = lldb.formatters.Logger.Logger()
396         self.node = node
397
398     left = property(_left_impl, None)
399     right = property(_right_impl, None)
400     parent = property(_parent_impl, None)
401     value = property(_value_impl, None)
402     is_null = property(_null_impl, None)
403     sbvalue = property(_sbvalue_impl, None)
404
405 # a Python implementation of the tree iterator used by libc++
406
407
408 class stdmap_iterator:
409
410     def tree_min(self, x):
411         logger = lldb.formatters.Logger.Logger()
412         steps = 0
413         if x.is_null:
414             return None
415         while (not x.left.is_null):
416             x = x.left
417             steps += 1
418             if steps > self.max_count:
419                 logger >> "Returning None - we overflowed"
420                 return None
421         return x
422
423     def tree_max(self, x):
424         logger = lldb.formatters.Logger.Logger()
425         if x.is_null:
426             return None
427         while (not x.right.is_null):
428             x = x.right
429         return x
430
431     def tree_is_left_child(self, x):
432         logger = lldb.formatters.Logger.Logger()
433         if x.is_null:
434             return None
435         return True if x.value == x.parent.left.value else False
436
437     def increment_node(self, node):
438         logger = lldb.formatters.Logger.Logger()
439         if node.is_null:
440             return None
441         if not node.right.is_null:
442             return self.tree_min(node.right)
443         steps = 0
444         while (not self.tree_is_left_child(node)):
445             steps += 1
446             if steps > self.max_count:
447                 logger >> "Returning None - we overflowed"
448                 return None
449             node = node.parent
450         return node.parent
451
452     def __init__(self, node, max_count=0):
453         logger = lldb.formatters.Logger.Logger()
454         # we convert the SBValue to an internal node object on entry
455         self.node = stdmap_iterator_node(node)
456         self.max_count = max_count
457
458     def value(self):
459         logger = lldb.formatters.Logger.Logger()
460         return self.node.sbvalue  # and return the SBValue back on exit
461
462     def next(self):
463         logger = lldb.formatters.Logger.Logger()
464         node = self.increment_node(self.node)
465         if node is not None and node.sbvalue.IsValid() and not(node.is_null):
466             self.node = node
467             return self.value()
468         else:
469             return None
470
471     def advance(self, N):
472         logger = lldb.formatters.Logger.Logger()
473         if N < 0:
474             return None
475         if N == 0:
476             return self.value()
477         if N == 1:
478             return self.next()
479         while N > 0:
480             if self.next() is None:
481                 return None
482             N = N - 1
483         return self.value()
484
485
486 class stdmap_SynthProvider:
487
488     def __init__(self, valobj, dict):
489         logger = lldb.formatters.Logger.Logger()
490         self.valobj = valobj
491         self.pointer_size = self.valobj.GetProcess().GetAddressByteSize()
492         self.count = None
493
494     def update(self):
495         logger = lldb.formatters.Logger.Logger()
496         self.count = None
497         try:
498             # we will set this to True if we find out that discovering a node in the map takes more steps than the overall size of the RB tree
499             # if this gets set to True, then we will merrily return None for
500             # any child from that moment on
501             self.garbage = False
502             self.tree = self.valobj.GetChildMemberWithName('__tree_')
503             self.root_node = self.tree.GetChildMemberWithName('__begin_node_')
504             # this data is either lazily-calculated, or cannot be inferred at this moment
505             # we still need to mark it as None, meaning "please set me ASAP"
506             self.data_type = None
507             self.data_size = None
508             self.skip_size = None
509         except:
510             pass
511
512     def num_children(self):
513         global _map_capping_size
514         logger = lldb.formatters.Logger.Logger()
515         if self.count is None:
516             self.count = self.num_children_impl()
517             if self.count > _map_capping_size:
518                 self.count = _map_capping_size
519         return self.count
520
521     def num_children_impl(self):
522         logger = lldb.formatters.Logger.Logger()
523         try:
524             return self.valobj.GetChildMemberWithName('__tree_').GetChildMemberWithName(
525                 '__pair3_').GetChildMemberWithName('__first_').GetValueAsUnsigned()
526         except:
527             return 0
528
529     def has_children(self):
530         return True
531
532     def get_data_type(self):
533         logger = lldb.formatters.Logger.Logger()
534         if self.data_type is None or self.data_size is None:
535             if self.num_children() == 0:
536                 return False
537             deref = self.root_node.Dereference()
538             if not(deref.IsValid()):
539                 return False
540             value = deref.GetChildMemberWithName('__value_')
541             if not(value.IsValid()):
542                 return False
543             self.data_type = value.GetType()
544             self.data_size = self.data_type.GetByteSize()
545             self.skip_size = None
546             return True
547         else:
548             return True
549
550     def get_value_offset(self, node):
551         logger = lldb.formatters.Logger.Logger()
552         if self.skip_size is None:
553             node_type = node.GetType()
554             fields_count = node_type.GetNumberOfFields()
555             for i in range(fields_count):
556                 field = node_type.GetFieldAtIndex(i)
557                 if field.GetName() == '__value_':
558                     self.skip_size = field.GetOffsetInBytes()
559                     break
560         return (self.skip_size is not None)
561
562     def get_child_index(self, name):
563         logger = lldb.formatters.Logger.Logger()
564         try:
565             return int(name.lstrip('[').rstrip(']'))
566         except:
567             return -1
568
569     def get_child_at_index(self, index):
570         logger = lldb.formatters.Logger.Logger()
571         logger >> "Retrieving child " + str(index)
572         if index < 0:
573             return None
574         if index >= self.num_children():
575             return None
576         if self.garbage:
577             logger >> "Returning None since this tree is garbage"
578             return None
579         try:
580             iterator = stdmap_iterator(
581                 self.root_node, max_count=self.num_children())
582             # the debug info for libc++ std::map is such that __begin_node_ has a very nice and useful type
583             # out of which we can grab the information we need - every other node has a less informative
584             # type which omits all value information and only contains housekeeping information for the RB tree
585             # hence, we need to know if we are at a node != 0, so that we can
586             # still get at the data
587             need_to_skip = (index > 0)
588             current = iterator.advance(index)
589             if current is None:
590                 logger >> "Tree is garbage - returning None"
591                 self.garbage = True
592                 return None
593             if self.get_data_type():
594                 if not(need_to_skip):
595                     current = current.Dereference()
596                     obj = current.GetChildMemberWithName('__value_')
597                     obj_data = obj.GetData()
598                     # make sure we have a valid offset for the next items
599                     self.get_value_offset(current)
600                     # we do not return __value_ because then we would end up with a child named
601                     # __value_ instead of [0]
602                     return self.valobj.CreateValueFromData(
603                         '[' + str(index) + ']', obj_data, self.data_type)
604                 else:
605                     # FIXME we need to have accessed item 0 before accessing
606                     # any other item!
607                     if self.skip_size is None:
608                         logger >> "You asked for item > 0 before asking for item == 0, I will fetch 0 now then retry"
609                         if self.get_child_at_index(0):
610                             return self.get_child_at_index(index)
611                         else:
612                             logger >> "item == 0 could not be found. sorry, nothing can be done here."
613                             return None
614                     return current.CreateChildAtOffset(
615                         '[' + str(index) + ']', self.skip_size, self.data_type)
616             else:
617                 logger >> "Unable to infer data-type - returning None (should mark tree as garbage here?)"
618                 return None
619         except Exception as err:
620             logger >> "Hit an exception: " + str(err)
621             return None
622
623 # Just an example: the actual summary is produced by a summary string:
624 # size=${svar%#}
625
626
627 def stdmap_SummaryProvider(valobj, dict):
628     prov = stdmap_SynthProvider(valobj, None)
629     return 'size=' + str(prov.num_children())
630
631
632 class stddeque_SynthProvider:
633
634     def __init__(self, valobj, d):
635         logger = lldb.formatters.Logger.Logger()
636         logger.write("init")
637         self.valobj = valobj
638         self.pointer_size = self.valobj.GetProcess().GetAddressByteSize()
639         self.count = None
640         try:
641             self.find_block_size()
642         except:
643             self.block_size = -1
644             self.element_size = -1
645         logger.write(
646             "block_size=%d, element_size=%d" %
647             (self.block_size, self.element_size))
648
649     def find_block_size(self):
650         # in order to use the deque we must have the block size, or else
651         # it's impossible to know what memory addresses are valid
652         self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
653         self.element_size = self.element_type.GetByteSize()
654         # The code says this, but there must be a better way:
655         # template <class _Tp, class _Allocator>
656         # class __deque_base {
657         #    static const difference_type __block_size = sizeof(value_type) < 256 ? 4096 / sizeof(value_type) : 16;
658         # }
659         if self.element_size < 256:
660             self.block_size = 4096 / self.element_size
661         else:
662             self.block_size = 16
663
664     def num_children(self):
665         global _deque_capping_size
666         logger = lldb.formatters.Logger.Logger()
667         if self.count is None:
668             return 0
669         return min(self.count, _deque_capping_size)
670
671     def has_children(self):
672         return True
673
674     def get_child_index(self, name):
675         logger = lldb.formatters.Logger.Logger()
676         try:
677             return int(name.lstrip('[').rstrip(']'))
678         except:
679             return -1
680
681     def get_child_at_index(self, index):
682         logger = lldb.formatters.Logger.Logger()
683         logger.write("Fetching child " + str(index))
684         if index < 0 or self.count is None:
685             return None
686         if index >= self.num_children():
687             return None
688         try:
689             i, j = divmod(self.start + index, self.block_size)
690             return self.first.CreateValueFromExpression(
691                 '[' + str(index) + ']', '*(*(%s + %d) + %d)' %
692                 (self.first.get_expr_path(), i, j))
693         except:
694             return None
695
696     def update(self):
697         logger = lldb.formatters.Logger.Logger()
698         try:
699             # A deque is effectively a two-dim array, with fixed width.
700             # 'map' contains pointers to the rows of this array. The
701             # full memory area allocated by the deque is delimited
702             # by 'first' and 'end_cap'. However, only a subset of this
703             # memory contains valid data since a deque may have some slack
704             # at the front and back in order to have O(1) insertion at
705             # both ends. The rows in active use are delimited by
706             # 'begin' and 'end'.
707             #
708             # To find the elements that are actually constructed, the 'start'
709             # variable tells which element in this NxM array is the 0th
710             # one, and the 'size' element gives the number of elements
711             # in the deque.
712             count = self.valobj.GetChildMemberWithName(
713                 '__size_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0)
714             # give up now if we cant access memory reliably
715             if self.block_size < 0:
716                 logger.write("block_size < 0")
717                 return
718             map_ = self.valobj.GetChildMemberWithName('__map_')
719             start = self.valobj.GetChildMemberWithName(
720                 '__start_').GetValueAsUnsigned(0)
721             first = map_.GetChildMemberWithName('__first_')
722             map_first = first.GetValueAsUnsigned(0)
723             map_begin = map_.GetChildMemberWithName(
724                 '__begin_').GetValueAsUnsigned(0)
725             map_end = map_.GetChildMemberWithName(
726                 '__end_').GetValueAsUnsigned(0)
727             map_endcap = map_.GetChildMemberWithName(
728                 '__end_cap_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0)
729             # check consistency
730             if not map_first <= map_begin <= map_end <= map_endcap:
731                 logger.write("map pointers are not monotonic")
732                 return
733             total_rows, junk = divmod(
734                 map_endcap - map_first, self.pointer_size)
735             if junk:
736                 logger.write("endcap-first doesnt align correctly")
737                 return
738             active_rows, junk = divmod(map_end - map_begin, self.pointer_size)
739             if junk:
740                 logger.write("end-begin doesnt align correctly")
741                 return
742             start_row, junk = divmod(map_begin - map_first, self.pointer_size)
743             if junk:
744                 logger.write("begin-first doesnt align correctly")
745                 return
746             if not start_row * \
747                     self.block_size <= start < (start_row + 1) * self.block_size:
748                 logger.write("0th element must be in the 'begin' row")
749                 return
750             end_row = start_row + active_rows
751             if not count:
752                 if active_rows:
753                     logger.write("empty deque but begin!=end")
754                     return
755             elif not (end_row - 1) * self.block_size <= start + count < end_row * self.block_size:
756                 logger.write("nth element must be before the 'end' row")
757                 return
758             logger.write(
759                 "update success: count=%r, start=%r, first=%r" %
760                 (count, start, first))
761             # if consistent, save all we really need:
762             self.count = count
763             self.start = start
764             self.first = first
765         except:
766             self.count = None
767             self.start = None
768             self.map_first = None
769             self.map_begin = None
770
771
772 class stdsharedptr_SynthProvider:
773
774     def __init__(self, valobj, d):
775         logger = lldb.formatters.Logger.Logger()
776         logger.write("init")
777         self.valobj = valobj
778         #self.element_ptr_type = self.valobj.GetType().GetTemplateArgumentType(0).GetPointerType()
779         self.ptr = None
780         self.cntrl = None
781         process = valobj.GetProcess()
782         self.endianness = process.GetByteOrder()
783         self.pointer_size = process.GetAddressByteSize()
784         self.count_type = valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
785
786     def num_children(self):
787         return 1
788
789     def has_children(self):
790         return True
791
792     def get_child_index(self, name):
793         if name == "__ptr_":
794             return 0
795         if name == "count":
796             return 1
797         if name == "weak_count":
798             return 2
799         return -1
800
801     def get_child_at_index(self, index):
802         if index == 0:
803             return self.ptr
804         if index == 1:
805             if self.cntrl is None:
806                 count = 0
807             else:
808                 count = 1 + \
809                     self.cntrl.GetChildMemberWithName('__shared_owners_').GetValueAsSigned()
810             return self.valobj.CreateValueFromData(
811                 "count", lldb.SBData.CreateDataFromUInt64Array(
812                     self.endianness, self.pointer_size, [count]), self.count_type)
813         if index == 2:
814             if self.cntrl is None:
815                 count = 0
816             else:
817                 count = 1 + \
818                     self.cntrl.GetChildMemberWithName('__shared_weak_owners_').GetValueAsSigned()
819             return self.valobj.CreateValueFromData(
820                 "weak_count", lldb.SBData.CreateDataFromUInt64Array(
821                     self.endianness, self.pointer_size, [count]), self.count_type)
822         return None
823
824     def update(self):
825         logger = lldb.formatters.Logger.Logger()
826         self.ptr = self.valobj.GetChildMemberWithName(
827             '__ptr_')  # .Cast(self.element_ptr_type)
828         cntrl = self.valobj.GetChildMemberWithName('__cntrl_')
829         if cntrl.GetValueAsUnsigned(0):
830             self.cntrl = cntrl.Dereference()
831         else:
832             self.cntrl = None
833
834 # we can use two different categories for old and new formatters - type names are different enough that we should make no confusion
835 # talking with libc++ developer: "std::__1::class_name is set in stone
836 # until we decide to change the ABI. That shouldn't happen within a 5 year
837 # time frame"
838
839
840 def __lldb_init_module(debugger, dict):
841     debugger.HandleCommand(
842         'type summary add -F libcxx.stdstring_SummaryProvider "std::__1::string" -w libcxx')
843     debugger.HandleCommand(
844         'type summary add -F libcxx.stdstring_SummaryProvider "std::__1::basic_string<char, class std::__1::char_traits<char>, class std::__1::allocator<char> >" -w libcxx')
845     debugger.HandleCommand(
846         'type synthetic add -l libcxx.stdvector_SynthProvider -x "^(std::__1::)vector<.+>$" -w libcxx')
847     debugger.HandleCommand(
848         'type summary add -F libcxx.stdvector_SummaryProvider -e -x "^(std::__1::)vector<.+>$" -w libcxx')
849     debugger.HandleCommand(
850         'type synthetic add -l libcxx.stdlist_SynthProvider -x "^(std::__1::)list<.+>$" -w libcxx')
851     debugger.HandleCommand(
852         'type summary add -F libcxx.stdlist_SummaryProvider -e -x "^(std::__1::)list<.+>$" -w libcxx')
853     debugger.HandleCommand(
854         'type synthetic add -l libcxx.stdmap_SynthProvider -x "^(std::__1::)map<.+> >$" -w libcxx')
855     debugger.HandleCommand(
856         'type summary add -F libcxx.stdmap_SummaryProvider -e -x "^(std::__1::)map<.+> >$" -w libcxx')
857     debugger.HandleCommand("type category enable libcxx")
858     debugger.HandleCommand(
859         'type synthetic add -l libcxx.stddeque_SynthProvider -x "^(std::__1::)deque<.+>$" -w libcxx')
860     debugger.HandleCommand(
861         'type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)shared_ptr<.+>$" -w libcxx')
862     # turns out the structs look the same, so weak_ptr can be handled the same!
863     debugger.HandleCommand(
864         'type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)weak_ptr<.+>$" -w libcxx')
865
866 _map_capping_size = 255
867 _list_capping_size = 255
868 _list_uses_loop_detector = True
869 _deque_capping_size = 255