1from __future__ import division
2import lldb.formatters.Logger
3
4# C++ STL formatters for LLDB
5# As there are many versions of the libstdc++, you are encouraged to look at the STL
6# implementation for your platform before relying on these formatters to do the right
7# thing for your setup
8
9def ForwardListSummaryProvider(valobj, dict):
10    list_capping_size = valobj.GetTarget().GetMaximumNumberOfChildrenToDisplay()
11    text = "size=" + str(valobj.GetNumChildren())
12    if valobj.GetNumChildren() > list_capping_size:
13        return "(capped) " + text
14    else:
15        return text
16
17def StdOptionalSummaryProvider(valobj, dict):
18    has_value = valobj.GetNumChildren() > 0
19    # We add wrapping spaces for consistency with the libcxx formatter
20    return " Has Value=" + ("true" if has_value else "false") + " "
21
22
23class StdOptionalSynthProvider:
24    def __init__(self, valobj, dict):
25        self.valobj = valobj
26
27    def update(self):
28        try:
29            self.payload = self.valobj.GetChildMemberWithName('_M_payload')
30            self.value = self.payload.GetChildMemberWithName('_M_payload')
31            self.has_value = self.payload.GetChildMemberWithName('_M_engaged').GetValueAsUnsigned(0) != 0
32        except:
33            self.has_value = False
34        return False
35
36
37    def num_children(self):
38        return 1 if self.has_value else 0
39
40    def get_child_index(self, name):
41        return 0
42
43    def get_child_at_index(self, index):
44        # some versions of libstdcpp have an additional _M_value child with the actual value
45        possible_value = self.value.GetChildMemberWithName('_M_value')
46        if possible_value.IsValid():
47            return possible_value.Clone('Value')
48        return self.value.Clone('Value')
49
50"""
51 This formatter can be applied to all
52 unordered map-like structures (unordered_map, unordered_multimap, unordered_set, unordered_multiset)
53"""
54class StdUnorderedMapSynthProvider:
55    def __init__(self, valobj, dict):
56        self.valobj = valobj
57        self.count = None
58        self.kind = self.get_object_kind(valobj)
59
60    def get_object_kind(self, valobj):
61        type_name = valobj.GetTypeName()
62        return "set" if "set" in type_name else "map"
63
64    def extract_type(self):
65        type = self.valobj.GetType()
66        # type of std::pair<key, value> is the first template
67        # argument type of the 4th template argument to std::map and
68        # 3rd template argument for std::set. That's why
69        # we need to know kind of the object
70        template_arg_num = 4 if self.kind == "map" else 3
71        allocator_type = type.GetTemplateArgumentType(template_arg_num)
72        data_type = allocator_type.GetTemplateArgumentType(0)
73        return data_type
74
75    def update(self):
76        # preemptively setting this to None - we might end up changing our mind
77        # later
78        self.count = None
79        try:
80            self.head = self.valobj.GetChildMemberWithName('_M_h')
81            self.before_begin = self.head.GetChildMemberWithName('_M_before_begin')
82            self.next = self.before_begin.GetChildMemberWithName('_M_nxt')
83            self.data_type = self.extract_type()
84            self.skip_size = self.next.GetType().GetByteSize()
85            self.data_size = self.data_type.GetByteSize()
86            if (not self.data_type.IsValid()) or (not self.next.IsValid()):
87                self.count = 0
88        except:
89            self.count = 0
90        return False
91
92    def get_child_index(self, name):
93        try:
94            return int(name.lstrip('[').rstrip(']'))
95        except:
96            return -1
97
98    def get_child_at_index(self, index):
99        logger = lldb.formatters.Logger.Logger()
100        logger >> "Being asked to fetch child[" + str(index) + "]"
101        if index < 0:
102            return None
103        if index >= self.num_children():
104            return None
105        try:
106            offset = index
107            current = self.next
108            while offset > 0:
109                current = current.GetChildMemberWithName('_M_nxt')
110                offset = offset - 1
111            return current.CreateChildAtOffset( '[' + str(index) + ']', self.skip_size, self.data_type)
112
113        except:
114            logger >> "Cannot get child"
115            return None
116
117    def num_children(self):
118        if self.count is None:
119            self.count = self.num_children_impl()
120        return self.count
121
122    def num_children_impl(self):
123        logger = lldb.formatters.Logger.Logger()
124        try:
125            count = self.head.GetChildMemberWithName('_M_element_count').GetValueAsUnsigned(0)
126            return count
127        except:
128            logger >> "Could not determine the size"
129            return 0
130
131
132class AbstractListSynthProvider:
133    def __init__(self, valobj, dict, has_prev):
134        '''
135        :param valobj: The value object of the list
136        :param dict: A dict with metadata provided by LLDB
137        :param has_prev: Whether the list supports a 'prev' pointer besides a 'next' one
138        '''
139        logger = lldb.formatters.Logger.Logger()
140        self.valobj = valobj
141        self.count = None
142        self.has_prev = has_prev
143        self.list_capping_size = self.valobj.GetTarget().GetMaximumNumberOfChildrenToDisplay()
144        logger >> "Providing synthetic children for a list named " + \
145            str(valobj.GetName())
146
147    def next_node(self, node):
148        logger = lldb.formatters.Logger.Logger()
149        return node.GetChildMemberWithName('_M_next')
150
151    def is_valid(self, node):
152        logger = lldb.formatters.Logger.Logger()
153        valid = self.value(self.next_node(node)) != self.get_end_of_list_address()
154        if valid:
155            logger >> "%s is valid" % str(self.valobj.GetName())
156        else:
157            logger >> "synthetic value is not valid"
158        return valid
159
160    def value(self, node):
161        logger = lldb.formatters.Logger.Logger()
162        value = node.GetValueAsUnsigned()
163        logger >> "synthetic value for {}: {}".format(
164            str(self.valobj.GetName()), value)
165        return value
166
167    # Floyd's cycle-finding algorithm
168    # try to detect if this list has a loop
169    def has_loop(self):
170        global _list_uses_loop_detector
171        logger = lldb.formatters.Logger.Logger()
172        if not _list_uses_loop_detector:
173            logger >> "Asked not to use loop detection"
174            return False
175        slow = self.next
176        fast1 = self.next
177        fast2 = self.next
178        while self.is_valid(slow):
179            slow_value = self.value(slow)
180            fast1 = self.next_node(fast2)
181            fast2 = self.next_node(fast1)
182            if self.value(fast1) == slow_value or self.value(
183                    fast2) == slow_value:
184                return True
185            slow = self.next_node(slow)
186        return False
187
188    def num_children(self):
189        logger = lldb.formatters.Logger.Logger()
190        if self.count is None:
191            # libstdc++ 6.0.21 added dedicated count field.
192            count_child = self.node.GetChildMemberWithName('_M_data')
193            if count_child and count_child.IsValid():
194                self.count = count_child.GetValueAsUnsigned(0)
195            if self.count is None:
196                self.count = self.num_children_impl()
197        return self.count
198
199    def num_children_impl(self):
200        logger = lldb.formatters.Logger.Logger()
201        try:
202            # After a std::list has been initialized, both next and prev will
203            # be non-NULL
204            next_val = self.next.GetValueAsUnsigned(0)
205            if next_val == 0:
206                return 0
207            if self.has_loop():
208                return 0
209            if self.has_prev:
210                prev_val = self.prev.GetValueAsUnsigned(0)
211                if prev_val == 0:
212                    return 0
213                if next_val == self.node_address:
214                    return 0
215                if next_val == prev_val:
216                    return 1
217            size = 1
218            current = self.next
219            while current.GetChildMemberWithName(
220                    '_M_next').GetValueAsUnsigned(0) != self.get_end_of_list_address():
221                current = current.GetChildMemberWithName('_M_next')
222                if not current.IsValid():
223                    break
224                size = size + 1
225                if size >= self.list_capping_size:
226                    break
227
228            return size
229        except:
230            logger >> "Error determining the size"
231            return 0
232
233    def get_child_index(self, name):
234        logger = lldb.formatters.Logger.Logger()
235        try:
236            return int(name.lstrip('[').rstrip(']'))
237        except:
238            return -1
239
240    def get_child_at_index(self, index):
241        logger = lldb.formatters.Logger.Logger()
242        logger >> "Fetching child " + str(index)
243        if index < 0:
244            return None
245        if index >= self.num_children():
246            return None
247        try:
248            offset = index
249            current = self.next
250            while offset > 0:
251                current = current.GetChildMemberWithName('_M_next')
252                offset = offset - 1
253            # C++ lists store the data of a node after its pointers. In the case of a forward list, there's just one pointer (next), and
254            # in the case of a double-linked list, there's an additional pointer (prev).
255            return current.CreateChildAtOffset(
256                '[' + str(index) + ']',
257               (2 if self.has_prev else 1) * current.GetType().GetByteSize(),
258                self.data_type)
259        except:
260            return None
261
262    def extract_type(self):
263        logger = lldb.formatters.Logger.Logger()
264        list_type = self.valobj.GetType().GetUnqualifiedType()
265        if list_type.IsReferenceType():
266            list_type = list_type.GetDereferencedType()
267        if list_type.GetNumberOfTemplateArguments() > 0:
268            return list_type.GetTemplateArgumentType(0)
269        return lldb.SBType()
270
271    def update(self):
272        logger = lldb.formatters.Logger.Logger()
273        # preemptively setting this to None - we might end up changing our mind
274        # later
275        self.count = None
276        try:
277            self.impl = self.valobj.GetChildMemberWithName('_M_impl')
278            self.data_type = self.extract_type()
279            if (not self.data_type.IsValid()) or (not self.impl.IsValid()):
280                self.count = 0
281            elif not self.updateNodes():
282                self.count = 0
283            else:
284                self.data_size = self.data_type.GetByteSize()
285        except:
286            self.count = 0
287        return False
288
289    '''
290    Method is used to extract the list pointers into the variables (e.g self.node, self.next, and optionally to self.prev)
291    and is mandatory to be overriden in each AbstractListSynthProvider subclass.
292    This should return True or False depending on wheter it found valid data.
293    '''
294    def updateNodes(self):
295        raise NotImplementedError
296
297    def has_children(self):
298        return True
299
300    '''
301     Method is used to identify if a node traversal has reached its end
302     and is mandatory to be overriden in each AbstractListSynthProvider subclass
303    '''
304    def get_end_of_list_address(self):
305        raise NotImplementedError
306
307
308class StdForwardListSynthProvider(AbstractListSynthProvider):
309
310    def __init__(self, valobj, dict):
311        has_prev = False
312        super().__init__(valobj, dict, has_prev)
313
314    def updateNodes(self):
315        self.node = self.impl.GetChildMemberWithName('_M_head')
316        self.next = self.node.GetChildMemberWithName('_M_next')
317        if (not self.node.IsValid()) or (not self.next.IsValid()):
318            return False
319        return True
320
321    def get_end_of_list_address(self):
322        return 0
323
324
325class StdListSynthProvider(AbstractListSynthProvider):
326
327    def __init__(self, valobj, dict):
328        has_prev = True
329        super().__init__(valobj, dict, has_prev)
330
331    def updateNodes(self):
332        self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0)
333        self.node = self.impl.GetChildMemberWithName('_M_node')
334        self.prev = self.node.GetChildMemberWithName('_M_prev')
335        self.next = self.node.GetChildMemberWithName('_M_next')
336        if self.node_address == 0 or (not self.node.IsValid()) or (not self.next.IsValid()) or (not self.prev.IsValid()):
337            return False
338        return True
339
340    def get_end_of_list_address(self):
341        return self.node_address
342
343
344class StdVectorSynthProvider:
345
346    class StdVectorImplementation(object):
347
348        def __init__(self, valobj):
349            self.valobj = valobj
350            self.count = None
351
352        def num_children(self):
353            if self.count is None:
354                self.count = self.num_children_impl()
355            return self.count
356
357        def num_children_impl(self):
358            try:
359                start_val = self.start.GetValueAsUnsigned(0)
360                finish_val = self.finish.GetValueAsUnsigned(0)
361                end_val = self.end.GetValueAsUnsigned(0)
362                # Before a vector has been constructed, it will contain bad values
363                # so we really need to be careful about the length we return since
364                # uninitialized data can cause us to return a huge number. We need
365                # to also check for any of the start, finish or end of storage values
366                # being zero (NULL). If any are, then this vector has not been
367                # initialized yet and we should return zero
368
369                # Make sure nothing is NULL
370                if start_val == 0 or finish_val == 0 or end_val == 0:
371                    return 0
372                # Make sure start is less than finish
373                if start_val >= finish_val:
374                    return 0
375                # Make sure finish is less than or equal to end of storage
376                if finish_val > end_val:
377                    return 0
378
379                # if we have a struct (or other data type that the compiler pads to native word size)
380                # this check might fail, unless the sizeof() we get is itself incremented to take the
381                # padding bytes into account - on current clang it looks like
382                # this is the case
383                num_children = (finish_val - start_val)
384                if (num_children % self.data_size) != 0:
385                    return 0
386                else:
387                    num_children = num_children // self.data_size
388                return num_children
389            except:
390                return 0
391
392        def get_child_at_index(self, index):
393            logger = lldb.formatters.Logger.Logger()
394            logger >> "Retrieving child " + str(index)
395            if index < 0:
396                return None
397            if index >= self.num_children():
398                return None
399            try:
400                offset = index * self.data_size
401                return self.start.CreateChildAtOffset(
402                    '[' + str(index) + ']', offset, self.data_type)
403            except:
404                return None
405
406        def update(self):
407            # preemptively setting this to None - we might end up changing our
408            # mind later
409            self.count = None
410            try:
411                impl = self.valobj.GetChildMemberWithName('_M_impl')
412                self.start = impl.GetChildMemberWithName('_M_start')
413                self.finish = impl.GetChildMemberWithName('_M_finish')
414                self.end = impl.GetChildMemberWithName('_M_end_of_storage')
415                self.data_type = self.start.GetType().GetPointeeType()
416                self.data_size = self.data_type.GetByteSize()
417                # if any of these objects is invalid, it means there is no
418                # point in trying to fetch anything
419                if self.start.IsValid() and self.finish.IsValid(
420                ) and self.end.IsValid() and self.data_type.IsValid():
421                    self.count = None
422                else:
423                    self.count = 0
424            except:
425                self.count = 0
426            return False
427
428    class StdVBoolImplementation(object):
429
430        def __init__(self, valobj, bool_type):
431            self.valobj = valobj
432            self.bool_type = bool_type
433            self.valid = False
434
435        def num_children(self):
436            if self.valid:
437                start = self.start_p.GetValueAsUnsigned(0)
438                finish = self.finish_p.GetValueAsUnsigned(0)
439                offset = self.offset.GetValueAsUnsigned(0)
440                if finish >= start:
441                    return (finish - start) * 8 + offset
442            return 0
443
444        def get_child_at_index(self, index):
445            if index >= self.num_children():
446                return None
447            element_type = self.start_p.GetType().GetPointeeType()
448            element_bits = 8 * element_type.GetByteSize()
449            element_offset = (index // element_bits) * \
450                element_type.GetByteSize()
451            bit_offset = index % element_bits
452            element = self.start_p.CreateChildAtOffset(
453                '[' + str(index) + ']', element_offset, element_type)
454            bit = element.GetValueAsUnsigned(0) & (1 << bit_offset)
455            if bit != 0:
456                value_expr = "(bool)true"
457            else:
458                value_expr = "(bool)false"
459            return self.valobj.CreateValueFromExpression(
460                "[%d]" % index, value_expr)
461
462        def update(self):
463            try:
464                m_impl = self.valobj.GetChildMemberWithName('_M_impl')
465                self.m_start = m_impl.GetChildMemberWithName('_M_start')
466                self.m_finish = m_impl.GetChildMemberWithName('_M_finish')
467                self.start_p = self.m_start.GetChildMemberWithName('_M_p')
468                self.finish_p = self.m_finish.GetChildMemberWithName('_M_p')
469                self.offset = self.m_finish.GetChildMemberWithName('_M_offset')
470                if self.offset.IsValid() and self.start_p.IsValid() and self.finish_p.IsValid():
471                    self.valid = True
472                else:
473                    self.valid = False
474            except:
475                self.valid = False
476            return False
477
478    def __init__(self, valobj, dict):
479        logger = lldb.formatters.Logger.Logger()
480        first_template_arg_type = valobj.GetType().GetTemplateArgumentType(0)
481        if str(first_template_arg_type.GetName()) == "bool":
482            self.impl = self.StdVBoolImplementation(
483                valobj, first_template_arg_type)
484        else:
485            self.impl = self.StdVectorImplementation(valobj)
486        logger >> "Providing synthetic children for a vector named " + \
487            str(valobj.GetName())
488
489    def num_children(self):
490        return self.impl.num_children()
491
492    def get_child_index(self, name):
493        try:
494            return int(name.lstrip('[').rstrip(']'))
495        except:
496            return -1
497
498    def get_child_at_index(self, index):
499        return self.impl.get_child_at_index(index)
500
501    def update(self):
502        return self.impl.update()
503
504    def has_children(self):
505        return True
506
507    """
508     This formatter can be applied to all
509     map-like structures (map, multimap, set, multiset)
510    """
511class StdMapLikeSynthProvider:
512
513    def __init__(self, valobj, dict):
514        logger = lldb.formatters.Logger.Logger()
515        self.valobj = valobj
516        self.count = None
517        self.kind = self.get_object_kind(valobj)
518        logger >> "Providing synthetic children for a " + self.kind + " named " + \
519            str(valobj.GetName())
520
521    def get_object_kind(self, valobj):
522        type_name = valobj.GetTypeName()
523        for kind in ["multiset", "multimap", "set", "map"]:
524           if kind in type_name:
525              return kind
526        return type_name
527
528    # we need this function as a temporary workaround for rdar://problem/10801549
529    # which prevents us from extracting the std::pair<K,V> SBType out of the template
530    # arguments for _Rep_Type _M_t in the object itself - because we have to make up the
531    # typename and then find it, we may hit the situation were std::string has multiple
532    # names but only one is actually referenced in the debug information. hence, we need
533    # to replace the longer versions of std::string with the shorter one in order to be able
534    # to find the type name
535    def fixup_class_name(self, class_name):
536        logger = lldb.formatters.Logger.Logger()
537        if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >':
538            return 'std::basic_string<char>', True
539        if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >':
540            return 'std::basic_string<char>', True
541        if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >':
542            return 'std::basic_string<char>', True
543        if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >':
544            return 'std::basic_string<char>', True
545        return class_name, False
546
547    def update(self):
548        logger = lldb.formatters.Logger.Logger()
549        # preemptively setting this to None - we might end up changing our mind
550        # later
551        self.count = None
552        try:
553            # we will set this to True if we find out that discovering a node in the object takes more steps than the overall size of the RB tree
554            # if this gets set to True, then we will merrily return None for
555            # any child from that moment on
556            self.garbage = False
557            self.Mt = self.valobj.GetChildMemberWithName('_M_t')
558            self.Mimpl = self.Mt.GetChildMemberWithName('_M_impl')
559            self.Mheader = self.Mimpl.GetChildMemberWithName('_M_header')
560            if not self.Mheader.IsValid():
561                self.count = 0
562            else:
563                map_type = self.valobj.GetType()
564                if map_type.IsReferenceType():
565                    logger >> "Dereferencing type"
566                    map_type = map_type.GetDereferencedType()
567
568                # Get the type of std::pair<key, value>. It is the first template
569                # argument type of the 4th template argument to std::map.
570                allocator_type = map_type.GetTemplateArgumentType(3)
571                self.data_type = allocator_type.GetTemplateArgumentType(0)
572                if not self.data_type:
573                    # GCC does not emit DW_TAG_template_type_parameter for
574                    # std::allocator<...>. For such a case, get the type of
575                    # std::pair from a member of std::map.
576                    rep_type = self.valobj.GetChildMemberWithName('_M_t').GetType()
577                    self.data_type = rep_type.GetTypedefedType().GetTemplateArgumentType(1)
578
579                # from libstdc++ implementation of _M_root for rbtree
580                self.Mroot = self.Mheader.GetChildMemberWithName('_M_parent')
581                self.data_size = self.data_type.GetByteSize()
582                self.skip_size = self.Mheader.GetType().GetByteSize()
583        except:
584            self.count = 0
585        return False
586
587    def num_children(self):
588        logger = lldb.formatters.Logger.Logger()
589        if self.count is None:
590            self.count = self.num_children_impl()
591        return self.count
592
593    def num_children_impl(self):
594        logger = lldb.formatters.Logger.Logger()
595        try:
596            root_ptr_val = self.node_ptr_value(self.Mroot)
597            if root_ptr_val == 0:
598                return 0
599            count = self.Mimpl.GetChildMemberWithName(
600                '_M_node_count').GetValueAsUnsigned(0)
601            logger >> "I have " + str(count) + " children available"
602            return count
603        except:
604            return 0
605
606    def get_child_index(self, name):
607        logger = lldb.formatters.Logger.Logger()
608        try:
609            return int(name.lstrip('[').rstrip(']'))
610        except:
611            return -1
612
613    def get_child_at_index(self, index):
614        logger = lldb.formatters.Logger.Logger()
615        logger >> "Being asked to fetch child[" + str(index) + "]"
616        if index < 0:
617            return None
618        if index >= self.num_children():
619            return None
620        if self.garbage:
621            logger >> "Returning None since we are a garbage tree"
622            return None
623        try:
624            offset = index
625            current = self.left(self.Mheader)
626            while offset > 0:
627                current = self.increment_node(current)
628                offset = offset - 1
629            # skip all the base stuff and get at the data
630            return current.CreateChildAtOffset(
631                '[' + str(index) + ']', self.skip_size, self.data_type)
632        except:
633            return None
634
635    # utility functions
636    def node_ptr_value(self, node):
637        logger = lldb.formatters.Logger.Logger()
638        return node.GetValueAsUnsigned(0)
639
640    def right(self, node):
641        logger = lldb.formatters.Logger.Logger()
642        return node.GetChildMemberWithName("_M_right")
643
644    def left(self, node):
645        logger = lldb.formatters.Logger.Logger()
646        return node.GetChildMemberWithName("_M_left")
647
648    def parent(self, node):
649        logger = lldb.formatters.Logger.Logger()
650        return node.GetChildMemberWithName("_M_parent")
651
652    # from libstdc++ implementation of iterator for rbtree
653    def increment_node(self, node):
654        logger = lldb.formatters.Logger.Logger()
655        max_steps = self.num_children()
656        if self.node_ptr_value(self.right(node)) != 0:
657            x = self.right(node)
658            max_steps -= 1
659            while self.node_ptr_value(self.left(x)) != 0:
660                x = self.left(x)
661                max_steps -= 1
662                logger >> str(max_steps) + " more to go before giving up"
663                if max_steps <= 0:
664                    self.garbage = True
665                    return None
666            return x
667        else:
668            x = node
669            y = self.parent(x)
670            max_steps -= 1
671            while(self.node_ptr_value(x) == self.node_ptr_value(self.right(y))):
672                x = y
673                y = self.parent(y)
674                max_steps -= 1
675                logger >> str(max_steps) + " more to go before giving up"
676                if max_steps <= 0:
677                    self.garbage = True
678                    return None
679            if self.node_ptr_value(self.right(x)) != self.node_ptr_value(y):
680                x = y
681            return x
682
683    def has_children(self):
684        return True
685
686_list_uses_loop_detector = True
687
688class StdDequeSynthProvider:
689    def __init__(self, valobj, d):
690        self.valobj = valobj
691        self.pointer_size = self.valobj.GetProcess().GetAddressByteSize()
692        self.count = None
693        self.block_size = -1
694        self.element_size = -1
695        self.find_block_size()
696
697
698    def find_block_size(self):
699        # in order to use the deque we must have the block size, or else
700        # it's impossible to know what memory addresses are valid
701        self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
702        if not self.element_type.IsValid():
703            return
704        self.element_size = self.element_type.GetByteSize()
705        # The block size (i.e. number of elements per subarray) is defined in
706        # this piece of code, so we need to replicate it.
707        #
708        # #define _GLIBCXX_DEQUE_BUF_SIZE 512
709        #
710        # return (__size < _GLIBCXX_DEQUE_BUF_SIZE
711	    #   ? size_t(_GLIBCXX_DEQUE_BUF_SIZE / __size) : size_t(1));
712        if self.element_size < 512:
713            self.block_size = 512 // self.element_size
714        else:
715            self.block_size = 1
716
717    def num_children(self):
718        if self.count is None:
719            return 0
720        return self.count
721
722    def has_children(self):
723        return True
724
725    def get_child_index(self, name):
726        try:
727            return int(name.lstrip('[').rstrip(']'))
728        except:
729            return -1
730
731    def get_child_at_index(self, index):
732        if index < 0 or self.count is None:
733            return None
734        if index >= self.num_children():
735            return None
736        try:
737            name = '[' + str(index) + ']'
738            # We first look for the element in the first subarray,
739            # which might be incomplete.
740            if index < self.first_node_size:
741                # The following statement is valid because self.first_elem is the pointer
742                # to the first element
743                return self.first_elem.CreateChildAtOffset(name, index * self.element_size, self.element_type)
744
745            # Now the rest of the subarrays except for maybe the last one
746            # are going to be complete, so the final expression is simpler
747            i, j = divmod(index - self.first_node_size, self.block_size)
748
749            # We first move to the beginning of the node/subarray were our element is
750            node = self.start_node.CreateChildAtOffset(
751                '',
752                (1 + i) * self.valobj.GetProcess().GetAddressByteSize(),
753                self.element_type.GetPointerType())
754            return node.CreateChildAtOffset(name, j * self.element_size, self.element_type)
755
756        except:
757            return None
758
759    def update(self):
760        logger = lldb.formatters.Logger.Logger()
761        self.count = 0
762        try:
763            # A deque is effectively a two-dim array, with fixed width.
764            # However, only a subset of this memory contains valid data
765            # since a deque may have some slack at the front and back in
766            # order to have O(1) insertion at both ends.
767            # The rows in active use are delimited by '_M_start' and
768            # '_M_finish'.
769            #
770            # To find the elements that are actually constructed, the 'start'
771            # variable tells which element in this NxM array is the 0th
772            # one.
773            if self.block_size < 0 or self.element_size < 0:
774                return False
775
776            count = 0
777
778            impl = self.valobj.GetChildMemberWithName('_M_impl')
779
780            # we calculate the size of the first node (i.e. first internal array)
781            self.start = impl.GetChildMemberWithName('_M_start')
782            self.start_node = self.start.GetChildMemberWithName('_M_node')
783            first_node_address = self.start_node.GetValueAsUnsigned(0)
784            first_node_last_elem = self.start.GetChildMemberWithName('_M_last').GetValueAsUnsigned(0)
785            self.first_elem = self.start.GetChildMemberWithName('_M_cur')
786            first_node_first_elem = self.first_elem.GetValueAsUnsigned(0)
787
788
789            finish = impl.GetChildMemberWithName('_M_finish')
790            last_node_address = finish.GetChildMemberWithName('_M_node').GetValueAsUnsigned(0)
791            last_node_first_elem = finish.GetChildMemberWithName('_M_first').GetValueAsUnsigned(0)
792            last_node_last_elem = finish.GetChildMemberWithName('_M_cur').GetValueAsUnsigned(0)
793
794            if first_node_first_elem == 0 or first_node_last_elem == 0 or first_node_first_elem > first_node_last_elem:
795                return False
796            if last_node_first_elem == 0 or last_node_last_elem == 0 or last_node_first_elem > last_node_last_elem:
797                return False
798
799
800            if last_node_address == first_node_address:
801                self.first_node_size = (last_node_last_elem - first_node_first_elem) // self.element_size
802                count += self.first_node_size
803            else:
804                self.first_node_size = (first_node_last_elem - first_node_first_elem) // self.element_size
805                count += self.first_node_size
806
807                # we calculate the size of the last node
808                finish = impl.GetChildMemberWithName('_M_finish')
809                last_node_address = finish.GetChildMemberWithName('_M_node').GetValueAsUnsigned(0)
810                count += (last_node_last_elem - last_node_first_elem) // self.element_size
811
812                # we calculate the size of the intermediate nodes
813                num_intermediate_nodes = (last_node_address - first_node_address - 1) // self.valobj.GetProcess().GetAddressByteSize()
814                count += self.block_size * num_intermediate_nodes
815            self.count = count
816        except:
817            pass
818        return False
819