1 import lldb
.formatters
.Logger
3 # C++ STL formatters for LLDB
4 # As there are many versions of the libstdc++, you are encouraged to look at the STL
5 # implementation for your platform before relying on these formatters to do the right
9 def 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
18 def StdOptionalSummaryProvider(valobj
, dict):
19 has_value
= valobj
.GetNumChildren() > 0
20 # We add wrapping spaces for consistency with the libcxx formatter
21 return " Has Value=" + ("true" if has_value
else "false") + " "
24 class StdOptionalSynthProvider
:
25 def __init__(self
, valobj
, dict):
30 self
.payload
= self
.valobj
.GetChildMemberWithName("_M_payload")
31 self
.value
= self
.payload
.GetChildMemberWithName("_M_payload")
33 self
.payload
.GetChildMemberWithName("_M_engaged").GetValueAsUnsigned(0)
37 self
.has_value
= False
40 def num_children(self
):
41 return 1 if self
.has_value
else 0
43 def get_child_index(self
, name
):
46 def get_child_at_index(self
, index
):
47 # some versions of libstdcpp have an additional _M_value child with the actual value
48 possible_value
= self
.value
.GetChildMemberWithName("_M_value")
49 if possible_value
.IsValid():
50 return possible_value
.Clone("Value")
51 return self
.value
.Clone("Value")
55 This formatter can be applied to all
56 unordered map-like structures (unordered_map, unordered_multimap, unordered_set, unordered_multiset)
60 class StdUnorderedMapSynthProvider
:
61 def __init__(self
, valobj
, dict):
64 self
.kind
= self
.get_object_kind(valobj
)
66 def get_object_kind(self
, valobj
):
67 type_name
= valobj
.GetTypeName()
68 return "set" if "set" in type_name
else "map"
70 def extract_type(self
):
71 type = self
.valobj
.GetType()
72 # type of std::pair<key, value> is the first template
73 # argument type of the 4th template argument to std::map and
74 # 3rd template argument for std::set. That's why
75 # we need to know kind of the object
76 template_arg_num
= 4 if self
.kind
== "map" else 3
77 allocator_type
= type.GetTemplateArgumentType(template_arg_num
)
78 data_type
= allocator_type
.GetTemplateArgumentType(0)
82 # preemptively setting this to None - we might end up changing our mind
86 self
.head
= self
.valobj
.GetChildMemberWithName("_M_h")
87 self
.before_begin
= self
.head
.GetChildMemberWithName("_M_before_begin")
88 self
.next
= self
.before_begin
.GetChildMemberWithName("_M_nxt")
89 self
.data_type
= self
.extract_type()
90 self
.skip_size
= self
.next
.GetType().GetByteSize()
91 self
.data_size
= self
.data_type
.GetByteSize()
92 if (not self
.data_type
.IsValid()) or (not self
.next
.IsValid()):
98 def get_child_index(self
, name
):
100 return int(name
.lstrip("[").rstrip("]"))
104 def get_child_at_index(self
, index
):
105 logger
= lldb
.formatters
.Logger
.Logger()
106 logger
>> "Being asked to fetch child[" + str(index
) + "]"
109 if index
>= self
.num_children():
115 current
= current
.GetChildMemberWithName("_M_nxt")
117 return current
.CreateChildAtOffset(
118 "[" + str(index
) + "]", self
.skip_size
, self
.data_type
122 logger
>> "Cannot get child"
125 def num_children(self
):
126 if self
.count
is None:
127 self
.count
= self
.num_children_impl()
130 def num_children_impl(self
):
131 logger
= lldb
.formatters
.Logger
.Logger()
133 count
= self
.head
.GetChildMemberWithName(
135 ).GetValueAsUnsigned(0)
138 logger
>> "Could not determine the size"
142 class AbstractListSynthProvider
:
143 def __init__(self
, valobj
, dict, has_prev
):
145 :param valobj: The value object of the list
146 :param dict: A dict with metadata provided by LLDB
147 :param has_prev: Whether the list supports a 'prev' pointer besides a 'next' one
149 logger
= lldb
.formatters
.Logger
.Logger()
152 self
.has_prev
= has_prev
153 self
.list_capping_size
= (
154 self
.valobj
.GetTarget().GetMaximumNumberOfChildrenToDisplay()
156 logger
>> "Providing synthetic children for a list named " + str(
160 def next_node(self
, node
):
161 logger
= lldb
.formatters
.Logger
.Logger()
162 return node
.GetChildMemberWithName("_M_next")
164 def is_valid(self
, node
):
165 logger
= lldb
.formatters
.Logger
.Logger()
166 valid
= self
.value(self
.next_node(node
)) != self
.get_end_of_list_address()
168 logger
>> "%s is valid" % str(self
.valobj
.GetName())
170 logger
>> "synthetic value is not valid"
173 def value(self
, node
):
174 logger
= lldb
.formatters
.Logger
.Logger()
175 value
= node
.GetValueAsUnsigned()
176 logger
>> "synthetic value for {}: {}".format(str(self
.valobj
.GetName()), value
)
179 # Floyd's cycle-finding algorithm
180 # try to detect if this list has a loop
182 global _list_uses_loop_detector
183 logger
= lldb
.formatters
.Logger
.Logger()
184 if not _list_uses_loop_detector
:
185 logger
>> "Asked not to use loop detection"
190 while self
.is_valid(slow
):
191 slow_value
= self
.value(slow
)
192 fast1
= self
.next_node(fast2
)
193 fast2
= self
.next_node(fast1
)
194 if self
.value(fast1
) == slow_value
or self
.value(fast2
) == slow_value
:
196 slow
= self
.next_node(slow
)
199 def num_children(self
):
200 logger
= lldb
.formatters
.Logger
.Logger()
201 if self
.count
is None:
202 # libstdc++ 6.0.21 added dedicated count field.
203 count_child
= self
.node
.GetChildMemberWithName("_M_data")
204 if count_child
and count_child
.IsValid():
205 self
.count
= count_child
.GetValueAsUnsigned(0)
206 if self
.count
is None:
207 self
.count
= self
.num_children_impl()
210 def num_children_impl(self
):
211 logger
= lldb
.formatters
.Logger
.Logger()
213 # After a std::list has been initialized, both next and prev will
215 next_val
= self
.next
.GetValueAsUnsigned(0)
221 prev_val
= self
.prev
.GetValueAsUnsigned(0)
224 if next_val
== self
.node_address
:
226 if next_val
== prev_val
:
231 current
.GetChildMemberWithName("_M_next").GetValueAsUnsigned(0)
232 != self
.get_end_of_list_address()
234 current
= current
.GetChildMemberWithName("_M_next")
235 if not current
.IsValid():
238 if size
>= self
.list_capping_size
:
243 logger
>> "Error determining the size"
246 def get_child_index(self
, name
):
247 logger
= lldb
.formatters
.Logger
.Logger()
249 return int(name
.lstrip("[").rstrip("]"))
253 def get_child_at_index(self
, index
):
254 logger
= lldb
.formatters
.Logger
.Logger()
255 logger
>> "Fetching child " + str(index
)
258 if index
>= self
.num_children():
264 current
= current
.GetChildMemberWithName("_M_next")
266 # 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
267 # in the case of a double-linked list, there's an additional pointer (prev).
268 return current
.CreateChildAtOffset(
269 "[" + str(index
) + "]",
270 (2 if self
.has_prev
else 1) * current
.GetType().GetByteSize(),
276 def extract_type(self
):
277 logger
= lldb
.formatters
.Logger
.Logger()
278 list_type
= self
.valobj
.GetType().GetUnqualifiedType()
279 if list_type
.IsReferenceType():
280 list_type
= list_type
.GetDereferencedType()
281 if list_type
.GetNumberOfTemplateArguments() > 0:
282 return list_type
.GetTemplateArgumentType(0)
286 logger
= lldb
.formatters
.Logger
.Logger()
287 # preemptively setting this to None - we might end up changing our mind
291 self
.impl
= self
.valobj
.GetChildMemberWithName("_M_impl")
292 self
.data_type
= self
.extract_type()
293 if (not self
.data_type
.IsValid()) or (not self
.impl
.IsValid()):
295 elif not self
.updateNodes():
298 self
.data_size
= self
.data_type
.GetByteSize()
304 Method is used to extract the list pointers into the variables (e.g self.node, self.next, and optionally to self.prev)
305 and is mandatory to be overriden in each AbstractListSynthProvider subclass.
306 This should return True or False depending on wheter it found valid data.
309 def updateNodes(self
):
310 raise NotImplementedError
312 def has_children(self
):
316 Method is used to identify if a node traversal has reached its end
317 and is mandatory to be overriden in each AbstractListSynthProvider subclass
320 def get_end_of_list_address(self
):
321 raise NotImplementedError
324 class StdForwardListSynthProvider(AbstractListSynthProvider
):
325 def __init__(self
, valobj
, dict):
327 super().__init
__(valobj
, dict, has_prev
)
329 def updateNodes(self
):
330 self
.node
= self
.impl
.GetChildMemberWithName("_M_head")
331 self
.next
= self
.node
.GetChildMemberWithName("_M_next")
332 if (not self
.node
.IsValid()) or (not self
.next
.IsValid()):
336 def get_end_of_list_address(self
):
340 class StdListSynthProvider(AbstractListSynthProvider
):
341 def __init__(self
, valobj
, dict):
343 super().__init
__(valobj
, dict, has_prev
)
345 def updateNodes(self
):
346 self
.node_address
= self
.valobj
.AddressOf().GetValueAsUnsigned(0)
347 self
.node
= self
.impl
.GetChildMemberWithName("_M_node")
348 self
.prev
= self
.node
.GetChildMemberWithName("_M_prev")
349 self
.next
= self
.node
.GetChildMemberWithName("_M_next")
351 self
.node_address
== 0
352 or (not self
.node
.IsValid())
353 or (not self
.next
.IsValid())
354 or (not self
.prev
.IsValid())
359 def get_end_of_list_address(self
):
360 return self
.node_address
363 class StdVectorSynthProvider
:
364 class StdVectorImplementation(object):
365 def __init__(self
, valobj
):
369 def num_children(self
):
370 if self
.count
is None:
371 self
.count
= self
.num_children_impl()
374 def num_children_impl(self
):
376 start_val
= self
.start
.GetValueAsUnsigned(0)
377 finish_val
= self
.finish
.GetValueAsUnsigned(0)
378 end_val
= self
.end
.GetValueAsUnsigned(0)
379 # Before a vector has been constructed, it will contain bad values
380 # so we really need to be careful about the length we return since
381 # uninitialized data can cause us to return a huge number. We need
382 # to also check for any of the start, finish or end of storage values
383 # being zero (NULL). If any are, then this vector has not been
384 # initialized yet and we should return zero
386 # Make sure nothing is NULL
387 if start_val
== 0 or finish_val
== 0 or end_val
== 0:
389 # Make sure start is less than finish
390 if start_val
>= finish_val
:
392 # Make sure finish is less than or equal to end of storage
393 if finish_val
> end_val
:
396 # if we have a struct (or other data type that the compiler pads to native word size)
397 # this check might fail, unless the sizeof() we get is itself incremented to take the
398 # padding bytes into account - on current clang it looks like
400 num_children
= finish_val
- start_val
401 if (num_children
% self
.data_size
) != 0:
404 num_children
= num_children
// self
.data_size
409 def get_child_at_index(self
, index
):
410 logger
= lldb
.formatters
.Logger
.Logger()
411 logger
>> "Retrieving child " + str(index
)
414 if index
>= self
.num_children():
417 offset
= index
* self
.data_size
418 return self
.start
.CreateChildAtOffset(
419 "[" + str(index
) + "]", offset
, self
.data_type
425 # preemptively setting this to None - we might end up changing our
429 impl
= self
.valobj
.GetChildMemberWithName("_M_impl")
430 self
.start
= impl
.GetChildMemberWithName("_M_start")
431 self
.finish
= impl
.GetChildMemberWithName("_M_finish")
432 self
.end
= impl
.GetChildMemberWithName("_M_end_of_storage")
433 self
.data_type
= self
.start
.GetType().GetPointeeType()
434 self
.data_size
= self
.data_type
.GetByteSize()
435 # if any of these objects is invalid, it means there is no
436 # point in trying to fetch anything
439 and self
.finish
.IsValid()
440 and self
.end
.IsValid()
441 and self
.data_type
.IsValid()
450 class StdVBoolImplementation(object):
451 def __init__(self
, valobj
, bool_type
):
453 self
.bool_type
= bool_type
456 def num_children(self
):
458 start
= self
.start_p
.GetValueAsUnsigned(0)
459 finish
= self
.finish_p
.GetValueAsUnsigned(0)
460 offset
= self
.offset
.GetValueAsUnsigned(0)
462 return (finish
- start
) * 8 + offset
465 def get_child_at_index(self
, index
):
466 if index
>= self
.num_children():
468 element_type
= self
.start_p
.GetType().GetPointeeType()
469 element_bits
= 8 * element_type
.GetByteSize()
470 element_offset
= (index
// element_bits
) * element_type
.GetByteSize()
471 bit_offset
= index
% element_bits
472 element
= self
.start_p
.CreateChildAtOffset(
473 "[" + str(index
) + "]", element_offset
, element_type
475 bit
= element
.GetValueAsUnsigned(0) & (1 << bit_offset
)
477 value_expr
= "(bool)true"
479 value_expr
= "(bool)false"
480 return self
.valobj
.CreateValueFromExpression("[%d]" % index
, value_expr
)
484 m_impl
= self
.valobj
.GetChildMemberWithName("_M_impl")
485 self
.m_start
= m_impl
.GetChildMemberWithName("_M_start")
486 self
.m_finish
= m_impl
.GetChildMemberWithName("_M_finish")
487 self
.start_p
= self
.m_start
.GetChildMemberWithName("_M_p")
488 self
.finish_p
= self
.m_finish
.GetChildMemberWithName("_M_p")
489 self
.offset
= self
.m_finish
.GetChildMemberWithName("_M_offset")
491 self
.offset
.IsValid()
492 and self
.start_p
.IsValid()
493 and self
.finish_p
.IsValid()
502 def __init__(self
, valobj
, dict):
503 logger
= lldb
.formatters
.Logger
.Logger()
504 first_template_arg_type
= valobj
.GetType().GetTemplateArgumentType(0)
505 if str(first_template_arg_type
.GetName()) == "bool":
506 self
.impl
= self
.StdVBoolImplementation(valobj
, first_template_arg_type
)
508 self
.impl
= self
.StdVectorImplementation(valobj
)
509 logger
>> "Providing synthetic children for a vector named " + str(
513 def num_children(self
):
514 return self
.impl
.num_children()
516 def get_child_index(self
, name
):
518 return int(name
.lstrip("[").rstrip("]"))
522 def get_child_at_index(self
, index
):
523 return self
.impl
.get_child_at_index(index
)
526 return self
.impl
.update()
528 def has_children(self
):
532 This formatter can be applied to all
533 map-like structures (map, multimap, set, multiset)
537 class StdMapLikeSynthProvider
:
538 def __init__(self
, valobj
, dict):
539 logger
= lldb
.formatters
.Logger
.Logger()
542 self
.kind
= self
.get_object_kind(valobj
)
545 >> "Providing synthetic children for a "
548 + str(valobj
.GetName())
551 def get_object_kind(self
, valobj
):
552 type_name
= valobj
.GetTypeName()
553 for kind
in ["multiset", "multimap", "set", "map"]:
554 if kind
in type_name
:
558 # we need this function as a temporary workaround for rdar://problem/10801549
559 # which prevents us from extracting the std::pair<K,V> SBType out of the template
560 # arguments for _Rep_Type _M_t in the object itself - because we have to make up the
561 # typename and then find it, we may hit the situation were std::string has multiple
562 # names but only one is actually referenced in the debug information. hence, we need
563 # to replace the longer versions of std::string with the shorter one in order to be able
564 # to find the type name
565 def fixup_class_name(self
, class_name
):
566 logger
= lldb
.formatters
.Logger
.Logger()
569 == "std::basic_string<char, std::char_traits<char>, std::allocator<char> >"
571 return "std::basic_string<char>", True
574 == "basic_string<char, std::char_traits<char>, std::allocator<char> >"
576 return "std::basic_string<char>", True
579 == "std::basic_string<char, std::char_traits<char>, std::allocator<char> >"
581 return "std::basic_string<char>", True
584 == "basic_string<char, std::char_traits<char>, std::allocator<char> >"
586 return "std::basic_string<char>", True
587 return class_name
, False
590 logger
= lldb
.formatters
.Logger
.Logger()
591 # preemptively setting this to None - we might end up changing our mind
595 # 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
596 # if this gets set to True, then we will merrily return None for
597 # any child from that moment on
599 self
.Mt
= self
.valobj
.GetChildMemberWithName("_M_t")
600 self
.Mimpl
= self
.Mt
.GetChildMemberWithName("_M_impl")
601 self
.Mheader
= self
.Mimpl
.GetChildMemberWithName("_M_header")
602 if not self
.Mheader
.IsValid():
605 map_type
= self
.valobj
.GetType()
606 if map_type
.IsReferenceType():
607 logger
>> "Dereferencing type"
608 map_type
= map_type
.GetDereferencedType()
610 # Get the type of std::pair<key, value>. It is the first template
611 # argument type of the 4th template argument to std::map.
612 allocator_type
= map_type
.GetTemplateArgumentType(3)
613 self
.data_type
= allocator_type
.GetTemplateArgumentType(0)
614 if not self
.data_type
:
615 # GCC does not emit DW_TAG_template_type_parameter for
616 # std::allocator<...>. For such a case, get the type of
617 # std::pair from a member of std::map.
618 rep_type
= self
.valobj
.GetChildMemberWithName("_M_t").GetType()
620 rep_type
.GetTypedefedType().GetTemplateArgumentType(1)
623 # from libstdc++ implementation of _M_root for rbtree
624 self
.Mroot
= self
.Mheader
.GetChildMemberWithName("_M_parent")
625 self
.data_size
= self
.data_type
.GetByteSize()
626 self
.skip_size
= self
.Mheader
.GetType().GetByteSize()
631 def num_children(self
):
632 logger
= lldb
.formatters
.Logger
.Logger()
633 if self
.count
is None:
634 self
.count
= self
.num_children_impl()
637 def num_children_impl(self
):
638 logger
= lldb
.formatters
.Logger
.Logger()
640 root_ptr_val
= self
.node_ptr_value(self
.Mroot
)
641 if root_ptr_val
== 0:
643 count
= self
.Mimpl
.GetChildMemberWithName(
645 ).GetValueAsUnsigned(0)
646 logger
>> "I have " + str(count
) + " children available"
651 def get_child_index(self
, name
):
652 logger
= lldb
.formatters
.Logger
.Logger()
654 return int(name
.lstrip("[").rstrip("]"))
658 def get_child_at_index(self
, index
):
659 logger
= lldb
.formatters
.Logger
.Logger()
660 logger
>> "Being asked to fetch child[" + str(index
) + "]"
663 if index
>= self
.num_children():
666 logger
>> "Returning None since we are a garbage tree"
670 current
= self
.left(self
.Mheader
)
672 current
= self
.increment_node(current
)
674 # skip all the base stuff and get at the data
675 return current
.CreateChildAtOffset(
676 "[" + str(index
) + "]", self
.skip_size
, self
.data_type
682 def node_ptr_value(self
, node
):
683 logger
= lldb
.formatters
.Logger
.Logger()
684 return node
.GetValueAsUnsigned(0)
686 def right(self
, node
):
687 logger
= lldb
.formatters
.Logger
.Logger()
688 return node
.GetChildMemberWithName("_M_right")
690 def left(self
, node
):
691 logger
= lldb
.formatters
.Logger
.Logger()
692 return node
.GetChildMemberWithName("_M_left")
694 def parent(self
, node
):
695 logger
= lldb
.formatters
.Logger
.Logger()
696 return node
.GetChildMemberWithName("_M_parent")
698 # from libstdc++ implementation of iterator for rbtree
699 def increment_node(self
, node
):
700 logger
= lldb
.formatters
.Logger
.Logger()
701 max_steps
= self
.num_children()
702 if self
.node_ptr_value(self
.right(node
)) != 0:
705 while self
.node_ptr_value(self
.left(x
)) != 0:
708 logger
>> str(max_steps
) + " more to go before giving up"
717 while self
.node_ptr_value(x
) == self
.node_ptr_value(self
.right(y
)):
721 logger
>> str(max_steps
) + " more to go before giving up"
725 if self
.node_ptr_value(self
.right(x
)) != self
.node_ptr_value(y
):
729 def has_children(self
):
733 _list_uses_loop_detector
= True
736 class StdDequeSynthProvider
:
737 def __init__(self
, valobj
, d
):
739 self
.pointer_size
= self
.valobj
.GetProcess().GetAddressByteSize()
742 self
.element_size
= -1
743 self
.find_block_size()
745 def find_block_size(self
):
746 # in order to use the deque we must have the block size, or else
747 # it's impossible to know what memory addresses are valid
748 self
.element_type
= self
.valobj
.GetType().GetTemplateArgumentType(0)
749 if not self
.element_type
.IsValid():
751 self
.element_size
= self
.element_type
.GetByteSize()
752 # The block size (i.e. number of elements per subarray) is defined in
753 # this piece of code, so we need to replicate it.
755 # #define _GLIBCXX_DEQUE_BUF_SIZE 512
757 # return (__size < _GLIBCXX_DEQUE_BUF_SIZE
758 # ? size_t(_GLIBCXX_DEQUE_BUF_SIZE / __size) : size_t(1));
759 if self
.element_size
< 512:
760 self
.block_size
= 512 // self
.element_size
764 def num_children(self
):
765 if self
.count
is None:
769 def has_children(self
):
772 def get_child_index(self
, name
):
774 return int(name
.lstrip("[").rstrip("]"))
778 def get_child_at_index(self
, index
):
779 if index
< 0 or self
.count
is None:
781 if index
>= self
.num_children():
784 name
= "[" + str(index
) + "]"
785 # We first look for the element in the first subarray,
786 # which might be incomplete.
787 if index
< self
.first_node_size
:
788 # The following statement is valid because self.first_elem is the pointer
789 # to the first element
790 return self
.first_elem
.CreateChildAtOffset(
791 name
, index
* self
.element_size
, self
.element_type
794 # Now the rest of the subarrays except for maybe the last one
795 # are going to be complete, so the final expression is simpler
796 i
, j
= divmod(index
- self
.first_node_size
, self
.block_size
)
798 # We first move to the beginning of the node/subarray were our element is
799 node
= self
.start_node
.CreateChildAtOffset(
801 (1 + i
) * self
.valobj
.GetProcess().GetAddressByteSize(),
802 self
.element_type
.GetPointerType(),
804 return node
.CreateChildAtOffset(
805 name
, j
* self
.element_size
, self
.element_type
812 logger
= lldb
.formatters
.Logger
.Logger()
815 # A deque is effectively a two-dim array, with fixed width.
816 # However, only a subset of this memory contains valid data
817 # since a deque may have some slack at the front and back in
818 # order to have O(1) insertion at both ends.
819 # The rows in active use are delimited by '_M_start' and
822 # To find the elements that are actually constructed, the 'start'
823 # variable tells which element in this NxM array is the 0th
825 if self
.block_size
< 0 or self
.element_size
< 0:
830 impl
= self
.valobj
.GetChildMemberWithName("_M_impl")
832 # we calculate the size of the first node (i.e. first internal array)
833 self
.start
= impl
.GetChildMemberWithName("_M_start")
834 self
.start_node
= self
.start
.GetChildMemberWithName("_M_node")
835 first_node_address
= self
.start_node
.GetValueAsUnsigned(0)
836 first_node_last_elem
= self
.start
.GetChildMemberWithName(
838 ).GetValueAsUnsigned(0)
839 self
.first_elem
= self
.start
.GetChildMemberWithName("_M_cur")
840 first_node_first_elem
= self
.first_elem
.GetValueAsUnsigned(0)
842 finish
= impl
.GetChildMemberWithName("_M_finish")
843 last_node_address
= finish
.GetChildMemberWithName(
845 ).GetValueAsUnsigned(0)
846 last_node_first_elem
= finish
.GetChildMemberWithName(
848 ).GetValueAsUnsigned(0)
849 last_node_last_elem
= finish
.GetChildMemberWithName(
851 ).GetValueAsUnsigned(0)
854 first_node_first_elem
== 0
855 or first_node_last_elem
== 0
856 or first_node_first_elem
> first_node_last_elem
860 last_node_first_elem
== 0
861 or last_node_last_elem
== 0
862 or last_node_first_elem
> last_node_last_elem
866 if last_node_address
== first_node_address
:
867 self
.first_node_size
= (
868 last_node_last_elem
- first_node_first_elem
869 ) // self
.element_size
870 count
+= self
.first_node_size
872 self
.first_node_size
= (
873 first_node_last_elem
- first_node_first_elem
874 ) // self
.element_size
875 count
+= self
.first_node_size
877 # we calculate the size of the last node
878 finish
= impl
.GetChildMemberWithName("_M_finish")
879 last_node_address
= finish
.GetChildMemberWithName(
881 ).GetValueAsUnsigned(0)
883 last_node_last_elem
- last_node_first_elem
884 ) // self
.element_size
886 # we calculate the size of the intermediate nodes
887 num_intermediate_nodes
= (
888 last_node_address
- first_node_address
- 1
889 ) // self
.valobj
.GetProcess().GetAddressByteSize()
890 count
+= self
.block_size
* num_intermediate_nodes
897 def VariantSummaryProvider(valobj
, dict):
898 raw_obj
= valobj
.GetNonSyntheticValue()
899 index_obj
= raw_obj
.GetChildMemberWithName("_M_index")
900 data_obj
= raw_obj
.GetChildMemberWithName("_M_u")
901 if not (index_obj
and index_obj
.IsValid() and data_obj
and data_obj
.IsValid()):
902 return "<Can't find _M_index or _M_u>"
904 def get_variant_npos_value(index_byte_size
):
905 if index_byte_size
== 1:
907 elif index_byte_size
== 2:
912 npos_value
= get_variant_npos_value(index_obj
.GetByteSize())
913 index
= index_obj
.GetValueAsUnsigned(0)
914 if index
== npos_value
:
917 # Invalid index can happen when the variant is not initialized yet.
918 template_arg_count
= data_obj
.GetType().GetNumberOfTemplateArguments()
919 if index
>= template_arg_count
:
922 active_type
= data_obj
.GetType().GetTemplateArgumentType(index
)
923 return f
" Active Type = {active_type.GetDisplayTypeName()} "
926 class VariantSynthProvider
:
927 def __init__(self
, valobj
, dict):
928 self
.raw_obj
= valobj
.GetNonSyntheticValue()
929 self
.is_valid
= False
935 self
.index
= self
.raw_obj
.GetChildMemberWithName(
937 ).GetValueAsSigned(-1)
938 self
.is_valid
= self
.index
!= -1
939 self
.data_obj
= self
.raw_obj
.GetChildMemberWithName("_M_u")
941 self
.is_valid
= False
944 def has_children(self
):
947 def num_children(self
):
948 return 1 if self
.is_valid
else 0
950 def get_child_index(self
, name
):
953 def get_child_at_index(self
, index
):
954 if not self
.is_valid
:
958 while cur
< self
.index
:
959 node
= node
.GetChildMemberWithName("_M_rest")
962 # _M_storage's type depends on variant field's type "_Type".
963 # 1. if '_Type' is literal type: _Type _M_storage.
964 # 2. otherwise, __gnu_cxx::__aligned_membuf<_Type> _M_storage.
966 # For 2. we have to cast it to underlying template _Type.
968 value
= node
.GetChildMemberWithName("_M_first").GetChildMemberWithName(
971 template_type
= value
.GetType().GetTemplateArgumentType(0)
973 # Literal type will return None for GetTemplateArgumentType(0)
976 and "__gnu_cxx::__aligned_membuf" in value
.GetType().GetDisplayTypeName()
977 and template_type
.IsValid()
979 value
= value
.Cast(template_type
)
982 return value
.Clone("Value")