1import lldb
2import 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
17def 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
30def is_short_string(value):
31    return True if (value & 1) == 0 else False
32
33
34def 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
43def 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
75class 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
152def stdvector_SummaryProvider(valobj, dict):
153    prov = stdvector_SynthProvider(valobj, None)
154    return 'size=' + str(prov.num_children())
155
156
157class 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
189class 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
229class 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%#}
357def 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
365class 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
408class 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
486class 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
627def stdmap_SummaryProvider(valobj, dict):
628    prov = stdmap_SynthProvider(valobj, None)
629    return 'size=' + str(prov.num_children())
630
631
632class 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 _get_value_of_compressed_pair(self, pair):
697        value = pair.GetChildMemberWithName("__value_")
698        if not value.IsValid():
699            # pre-r300140 member name
700            value = pair.GetChildMemberWithName("__first_")
701        return value.GetValueAsUnsigned(0)
702
703    def update(self):
704        logger = lldb.formatters.Logger.Logger()
705        try:
706            # A deque is effectively a two-dim array, with fixed width.
707            # 'map' contains pointers to the rows of this array. The
708            # full memory area allocated by the deque is delimited
709            # by 'first' and 'end_cap'. However, only a subset of this
710            # memory contains valid data since a deque may have some slack
711            # at the front and back in order to have O(1) insertion at
712            # both ends. The rows in active use are delimited by
713            # 'begin' and 'end'.
714            #
715            # To find the elements that are actually constructed, the 'start'
716            # variable tells which element in this NxM array is the 0th
717            # one, and the 'size' element gives the number of elements
718            # in the deque.
719            count = self._get_value_of_compressed_pair(
720                    self.valobj.GetChildMemberWithName('__size_'))
721            # give up now if we cant access memory reliably
722            if self.block_size < 0:
723                logger.write("block_size < 0")
724                return
725            map_ = self.valobj.GetChildMemberWithName('__map_')
726            start = self.valobj.GetChildMemberWithName(
727                '__start_').GetValueAsUnsigned(0)
728            first = map_.GetChildMemberWithName('__first_')
729            map_first = first.GetValueAsUnsigned(0)
730            map_begin = map_.GetChildMemberWithName(
731                '__begin_').GetValueAsUnsigned(0)
732            map_end = map_.GetChildMemberWithName(
733                '__end_').GetValueAsUnsigned(0)
734            map_endcap = self._get_value_of_compressed_pair(
735                    map_.GetChildMemberWithName( '__end_cap_'))
736            # check consistency
737            if not map_first <= map_begin <= map_end <= map_endcap:
738                logger.write("map pointers are not monotonic")
739                return
740            total_rows, junk = divmod(
741                map_endcap - map_first, self.pointer_size)
742            if junk:
743                logger.write("endcap-first doesnt align correctly")
744                return
745            active_rows, junk = divmod(map_end - map_begin, self.pointer_size)
746            if junk:
747                logger.write("end-begin doesnt align correctly")
748                return
749            start_row, junk = divmod(map_begin - map_first, self.pointer_size)
750            if junk:
751                logger.write("begin-first doesnt align correctly")
752                return
753            if not start_row * \
754                    self.block_size <= start < (start_row + 1) * self.block_size:
755                logger.write("0th element must be in the 'begin' row")
756                return
757            end_row = start_row + active_rows
758            if not count:
759                if active_rows:
760                    logger.write("empty deque but begin!=end")
761                    return
762            elif not (end_row - 1) * self.block_size <= start + count < end_row * self.block_size:
763                logger.write("nth element must be before the 'end' row")
764                return
765            logger.write(
766                "update success: count=%r, start=%r, first=%r" %
767                (count, start, first))
768            # if consistent, save all we really need:
769            self.count = count
770            self.start = start
771            self.first = first
772        except:
773            self.count = None
774            self.start = None
775            self.map_first = None
776            self.map_begin = None
777
778
779class stdsharedptr_SynthProvider:
780
781    def __init__(self, valobj, d):
782        logger = lldb.formatters.Logger.Logger()
783        logger.write("init")
784        self.valobj = valobj
785        #self.element_ptr_type = self.valobj.GetType().GetTemplateArgumentType(0).GetPointerType()
786        self.ptr = None
787        self.cntrl = None
788        process = valobj.GetProcess()
789        self.endianness = process.GetByteOrder()
790        self.pointer_size = process.GetAddressByteSize()
791        self.count_type = valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
792
793    def num_children(self):
794        return 1
795
796    def has_children(self):
797        return True
798
799    def get_child_index(self, name):
800        if name == "__ptr_":
801            return 0
802        if name == "count":
803            return 1
804        if name == "weak_count":
805            return 2
806        return -1
807
808    def get_child_at_index(self, index):
809        if index == 0:
810            return self.ptr
811        if index == 1:
812            if self.cntrl is None:
813                count = 0
814            else:
815                count = 1 + \
816                    self.cntrl.GetChildMemberWithName('__shared_owners_').GetValueAsSigned()
817            return self.valobj.CreateValueFromData(
818                "count", lldb.SBData.CreateDataFromUInt64Array(
819                    self.endianness, self.pointer_size, [count]), self.count_type)
820        if index == 2:
821            if self.cntrl is None:
822                count = 0
823            else:
824                count = 1 + \
825                    self.cntrl.GetChildMemberWithName('__shared_weak_owners_').GetValueAsSigned()
826            return self.valobj.CreateValueFromData(
827                "weak_count", lldb.SBData.CreateDataFromUInt64Array(
828                    self.endianness, self.pointer_size, [count]), self.count_type)
829        return None
830
831    def update(self):
832        logger = lldb.formatters.Logger.Logger()
833        self.ptr = self.valobj.GetChildMemberWithName(
834            '__ptr_')  # .Cast(self.element_ptr_type)
835        cntrl = self.valobj.GetChildMemberWithName('__cntrl_')
836        if cntrl.GetValueAsUnsigned(0):
837            self.cntrl = cntrl.Dereference()
838        else:
839            self.cntrl = None
840
841# we can use two different categories for old and new formatters - type names are different enough that we should make no confusion
842# talking with libc++ developer: "std::__1::class_name is set in stone
843# until we decide to change the ABI. That shouldn't happen within a 5 year
844# time frame"
845
846
847def __lldb_init_module(debugger, dict):
848    debugger.HandleCommand(
849        'type summary add -F libcxx.stdstring_SummaryProvider "std::__1::string" -w libcxx')
850    debugger.HandleCommand(
851        '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')
852    debugger.HandleCommand(
853        'type synthetic add -l libcxx.stdvector_SynthProvider -x "^(std::__1::)vector<.+>$" -w libcxx')
854    debugger.HandleCommand(
855        'type summary add -F libcxx.stdvector_SummaryProvider -e -x "^(std::__1::)vector<.+>$" -w libcxx')
856    debugger.HandleCommand(
857        'type synthetic add -l libcxx.stdlist_SynthProvider -x "^(std::__1::)list<.+>$" -w libcxx')
858    debugger.HandleCommand(
859        'type summary add -F libcxx.stdlist_SummaryProvider -e -x "^(std::__1::)list<.+>$" -w libcxx')
860    debugger.HandleCommand(
861        'type synthetic add -l libcxx.stdmap_SynthProvider -x "^(std::__1::)map<.+> >$" -w libcxx')
862    debugger.HandleCommand(
863        'type summary add -F libcxx.stdmap_SummaryProvider -e -x "^(std::__1::)map<.+> >$" -w libcxx')
864    debugger.HandleCommand("type category enable libcxx")
865    debugger.HandleCommand(
866        'type synthetic add -l libcxx.stddeque_SynthProvider -x "^(std::__1::)deque<.+>$" -w libcxx')
867    debugger.HandleCommand(
868        'type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)shared_ptr<.+>$" -w libcxx')
869    # turns out the structs look the same, so weak_ptr can be handled the same!
870    debugger.HandleCommand(
871        'type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)weak_ptr<.+>$" -w libcxx')
872
873_map_capping_size = 255
874_list_capping_size = 255
875_list_uses_loop_detector = True
876_deque_capping_size = 255
877