2 import lldb.formatters.Logger
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
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
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
17 def make_string(F, L):
24 strval = strval + chr(V % 256)
25 return '"' + strval + '"'
27 # if we ever care about big-endian, these two functions might need to change
30 def is_short_string(value):
31 return True if (value & 1) == 0 else False
34 def extract_short_size(value):
35 return ((value >> 1) % 256)
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
43 def stdstring_SummaryProvider(valobj, dict):
44 logger = lldb.formatters.Logger.Logger()
45 r = valobj.GetChildAtIndex(0)
46 B = r.GetChildAtIndex(0)
47 first = B.GetChildAtIndex(0)
48 D = first.GetChildAtIndex(0)
49 l = D.GetChildAtIndex(0)
50 s = D.GetChildAtIndex(1)
51 D20 = s.GetChildAtIndex(0)
52 size_mode = D20.GetChildAtIndex(0).GetValueAsUnsigned(0)
53 if is_short_string(size_mode):
54 size = extract_short_size(size_mode)
55 return make_string(s.GetChildAtIndex(1), size)
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
64 data = data_ptr.GetPointeeData(0, size)
67 error = lldb.SBError()
68 strval = data.GetString(error, 0)
70 return '<error:' + error.GetCString() + '>'
72 return '"' + strval + '"'
75 class stdvector_SynthProvider:
77 def __init__(self, valobj, dict):
78 logger = lldb.formatters.Logger.Logger()
81 def num_children(self):
82 logger = lldb.formatters.Logger.Logger()
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
93 # Make sure nothing is NULL
94 if start_val == 0 or finish_val == 0:
96 # Make sure start is less than finish
97 if start_val >= finish_val:
100 num_children = (finish_val - start_val)
101 if (num_children % self.data_size) != 0:
104 num_children = num_children / self.data_size
109 def get_child_index(self, name):
110 logger = lldb.formatters.Logger.Logger()
112 return int(name.lstrip('[').rstrip(']'))
116 def get_child_at_index(self, index):
117 logger = lldb.formatters.Logger.Logger()
118 logger >> "Retrieving child " + str(index)
121 if index >= self.num_children():
124 offset = index * self.data_size
125 return self.start.CreateChildAtOffset(
126 '[' + str(index) + ']', offset, self.data_type)
131 logger = lldb.formatters.Logger.Logger()
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
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()
145 def has_children(self):
148 # Just an example: the actual summary is produced by a summary string:
152 def stdvector_SummaryProvider(valobj, dict):
153 prov = stdvector_SynthProvider(valobj, None)
154 return 'size=' + str(prov.num_children())
159 def __init__(self, entry):
160 logger = lldb.formatters.Logger.Logger()
163 def _next_impl(self):
164 logger = lldb.formatters.Logger.Logger()
165 return stdlist_entry(self.entry.GetChildMemberWithName('__next_'))
167 def _prev_impl(self):
168 logger = lldb.formatters.Logger.Logger()
169 return stdlist_entry(self.entry.GetChildMemberWithName('__prev_'))
171 def _value_impl(self):
172 logger = lldb.formatters.Logger.Logger()
173 return self.entry.GetValueAsUnsigned(0)
175 def _isnull_impl(self):
176 logger = lldb.formatters.Logger.Logger()
177 return self._value_impl() == 0
179 def _sbvalue_impl(self):
180 logger = lldb.formatters.Logger.Logger()
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)
189 class stdlist_iterator:
191 def increment_node(self, node):
192 logger = lldb.formatters.Logger.Logger()
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)
203 logger = lldb.formatters.Logger.Logger()
204 return self.node.sbvalue # and return the SBValue back on exit
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):
215 def advance(self, N):
216 logger = lldb.formatters.Logger.Logger()
229 class stdlist_SynthProvider:
231 def __init__(self, valobj, dict):
232 logger = lldb.formatters.Logger.Logger()
236 def next_node(self, node):
237 logger = lldb.formatters.Logger.Logger()
238 return node.GetChildMemberWithName('__next_')
240 def value(self, node):
241 logger = lldb.formatters.Logger.Logger()
242 return node.GetValueAsUnsigned()
244 # Floyd's cycle-finding algorithm
245 # try to detect if this list has a loop
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"
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
259 if fast1.value == slow_value or fast2.value == slow_value:
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
273 def num_children_impl(self):
274 global _list_capping_size
275 logger = lldb.formatters.Logger.Logger()
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
281 if next_val == 0 or prev_val == 0:
283 if next_val == self.node_address:
285 if next_val == prev_val:
290 current = stdlist_entry(self.head)
291 while current.next.value != self.node_address:
293 current = current.next
294 if size > _list_capping_size:
295 return _list_capping_size
300 def get_child_index(self, name):
301 logger = lldb.formatters.Logger.Logger()
303 return int(name.lstrip('[').rstrip(']'))
307 def get_child_at_index(self, index):
308 logger = lldb.formatters.Logger.Logger()
309 logger >> "Fetching child " + str(index)
312 if index >= self.num_children():
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 -
320 obj = current.GetChildMemberWithName('__value_')
321 obj_data = obj.GetData()
322 return self.valobj.CreateValueFromData(
323 '[' + str(index) + ']', obj_data, self.data_type)
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)
339 logger = lldb.formatters.Logger.Logger()
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()
351 def has_children(self):
355 # Just an example: the actual summary is produced by a summary string:
357 def stdlist_SummaryProvider(valobj, dict):
358 prov = stdlist_SynthProvider(valobj, None)
359 return 'size=' + str(prov.num_children())
361 # a tree node - this class makes the syntax in the actual iterator nicer
362 # to read and maintain
365 class stdmap_iterator_node:
367 def _left_impl(self):
368 logger = lldb.formatters.Logger.Logger()
369 return stdmap_iterator_node(
370 self.node.GetChildMemberWithName("__left_"))
372 def _right_impl(self):
373 logger = lldb.formatters.Logger.Logger()
374 return stdmap_iterator_node(
375 self.node.GetChildMemberWithName("__right_"))
377 def _parent_impl(self):
378 logger = lldb.formatters.Logger.Logger()
379 return stdmap_iterator_node(
380 self.node.GetChildMemberWithName("__parent_"))
382 def _value_impl(self):
383 logger = lldb.formatters.Logger.Logger()
384 return self.node.GetValueAsUnsigned(0)
386 def _sbvalue_impl(self):
387 logger = lldb.formatters.Logger.Logger()
390 def _null_impl(self):
391 logger = lldb.formatters.Logger.Logger()
392 return self.value == 0
394 def __init__(self, node):
395 logger = lldb.formatters.Logger.Logger()
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)
405 # a Python implementation of the tree iterator used by libc++
408 class stdmap_iterator:
410 def tree_min(self, x):
411 logger = lldb.formatters.Logger.Logger()
415 while (not x.left.is_null):
418 if steps > self.max_count:
419 logger >> "Returning None - we overflowed"
423 def tree_max(self, x):
424 logger = lldb.formatters.Logger.Logger()
427 while (not x.right.is_null):
431 def tree_is_left_child(self, x):
432 logger = lldb.formatters.Logger.Logger()
435 return True if x.value == x.parent.left.value else False
437 def increment_node(self, node):
438 logger = lldb.formatters.Logger.Logger()
441 if not node.right.is_null:
442 return self.tree_min(node.right)
444 while (not self.tree_is_left_child(node)):
446 if steps > self.max_count:
447 logger >> "Returning None - we overflowed"
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
459 logger = lldb.formatters.Logger.Logger()
460 return self.node.sbvalue # and return the SBValue back on exit
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):
471 def advance(self, N):
472 logger = lldb.formatters.Logger.Logger()
480 if self.next() is None:
486 class stdmap_SynthProvider:
488 def __init__(self, valobj, dict):
489 logger = lldb.formatters.Logger.Logger()
491 self.pointer_size = self.valobj.GetProcess().GetAddressByteSize()
495 logger = lldb.formatters.Logger.Logger()
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
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
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
521 def num_children_impl(self):
522 logger = lldb.formatters.Logger.Logger()
524 return self.valobj.GetChildMemberWithName('__tree_').GetChildMemberWithName(
525 '__pair3_').GetChildMemberWithName('__first_').GetValueAsUnsigned()
529 def has_children(self):
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:
537 deref = self.root_node.Dereference()
538 if not(deref.IsValid()):
540 value = deref.GetChildMemberWithName('__value_')
541 if not(value.IsValid()):
543 self.data_type = value.GetType()
544 self.data_size = self.data_type.GetByteSize()
545 self.skip_size = None
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()
560 return (self.skip_size is not None)
562 def get_child_index(self, name):
563 logger = lldb.formatters.Logger.Logger()
565 return int(name.lstrip('[').rstrip(']'))
569 def get_child_at_index(self, index):
570 logger = lldb.formatters.Logger.Logger()
571 logger >> "Retrieving child " + str(index)
574 if index >= self.num_children():
577 logger >> "Returning None since this tree is garbage"
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)
590 logger >> "Tree is garbage - returning 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)
605 # FIXME we need to have accessed item 0 before accessing
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)
612 logger >> "item == 0 could not be found. sorry, nothing can be done here."
614 return current.CreateChildAtOffset(
615 '[' + str(index) + ']', self.skip_size, self.data_type)
617 logger >> "Unable to infer data-type - returning None (should mark tree as garbage here?)"
619 except Exception as err:
620 logger >> "Hit an exception: " + str(err)
623 # Just an example: the actual summary is produced by a summary string:
627 def stdmap_SummaryProvider(valobj, dict):
628 prov = stdmap_SynthProvider(valobj, None)
629 return 'size=' + str(prov.num_children())
632 class stddeque_SynthProvider:
634 def __init__(self, valobj, d):
635 logger = lldb.formatters.Logger.Logger()
638 self.pointer_size = self.valobj.GetProcess().GetAddressByteSize()
641 self.find_block_size()
644 self.element_size = -1
646 "block_size=%d, element_size=%d" %
647 (self.block_size, self.element_size))
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;
659 if self.element_size < 256:
660 self.block_size = 4096 / self.element_size
664 def num_children(self):
665 global _deque_capping_size
666 logger = lldb.formatters.Logger.Logger()
667 if self.count is None:
669 return min(self.count, _deque_capping_size)
671 def has_children(self):
674 def get_child_index(self, name):
675 logger = lldb.formatters.Logger.Logger()
677 return int(name.lstrip('[').rstrip(']'))
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:
686 if index >= self.num_children():
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))
697 logger = lldb.formatters.Logger.Logger()
699 # A deque is effectively a two-dim array, with fixed width.
700 # 'map' contains pointers to the rows of this array. The
701 # full memory area allocated by the deque is delimited
702 # by 'first' and 'end_cap'. However, only a subset of this
703 # memory contains valid data since a deque may have some slack
704 # at the front and back in order to have O(1) insertion at
705 # both ends. The rows in active use are delimited by
708 # To find the elements that are actually constructed, the 'start'
709 # variable tells which element in this NxM array is the 0th
710 # one, and the 'size' element gives the number of elements
712 count = self.valobj.GetChildMemberWithName(
713 '__size_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0)
714 # give up now if we cant access memory reliably
715 if self.block_size < 0:
716 logger.write("block_size < 0")
718 map_ = self.valobj.GetChildMemberWithName('__map_')
719 start = self.valobj.GetChildMemberWithName(
720 '__start_').GetValueAsUnsigned(0)
721 first = map_.GetChildMemberWithName('__first_')
722 map_first = first.GetValueAsUnsigned(0)
723 map_begin = map_.GetChildMemberWithName(
724 '__begin_').GetValueAsUnsigned(0)
725 map_end = map_.GetChildMemberWithName(
726 '__end_').GetValueAsUnsigned(0)
727 map_endcap = map_.GetChildMemberWithName(
728 '__end_cap_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0)
730 if not map_first <= map_begin <= map_end <= map_endcap:
731 logger.write("map pointers are not monotonic")
733 total_rows, junk = divmod(
734 map_endcap - map_first, self.pointer_size)
736 logger.write("endcap-first doesnt align correctly")
738 active_rows, junk = divmod(map_end - map_begin, self.pointer_size)
740 logger.write("end-begin doesnt align correctly")
742 start_row, junk = divmod(map_begin - map_first, self.pointer_size)
744 logger.write("begin-first doesnt align correctly")
747 self.block_size <= start < (start_row + 1) * self.block_size:
748 logger.write("0th element must be in the 'begin' row")
750 end_row = start_row + active_rows
753 logger.write("empty deque but begin!=end")
755 elif not (end_row - 1) * self.block_size <= start + count < end_row * self.block_size:
756 logger.write("nth element must be before the 'end' row")
759 "update success: count=%r, start=%r, first=%r" %
760 (count, start, first))
761 # if consistent, save all we really need:
768 self.map_first = None
769 self.map_begin = None
772 class stdsharedptr_SynthProvider:
774 def __init__(self, valobj, d):
775 logger = lldb.formatters.Logger.Logger()
778 #self.element_ptr_type = self.valobj.GetType().GetTemplateArgumentType(0).GetPointerType()
781 process = valobj.GetProcess()
782 self.endianness = process.GetByteOrder()
783 self.pointer_size = process.GetAddressByteSize()
784 self.count_type = valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
786 def num_children(self):
789 def has_children(self):
792 def get_child_index(self, name):
797 if name == "weak_count":
801 def get_child_at_index(self, index):
805 if self.cntrl is None:
809 self.cntrl.GetChildMemberWithName('__shared_owners_').GetValueAsSigned()
810 return self.valobj.CreateValueFromData(
811 "count", lldb.SBData.CreateDataFromUInt64Array(
812 self.endianness, self.pointer_size, [count]), self.count_type)
814 if self.cntrl is None:
818 self.cntrl.GetChildMemberWithName('__shared_weak_owners_').GetValueAsSigned()
819 return self.valobj.CreateValueFromData(
820 "weak_count", lldb.SBData.CreateDataFromUInt64Array(
821 self.endianness, self.pointer_size, [count]), self.count_type)
825 logger = lldb.formatters.Logger.Logger()
826 self.ptr = self.valobj.GetChildMemberWithName(
827 '__ptr_') # .Cast(self.element_ptr_type)
828 cntrl = self.valobj.GetChildMemberWithName('__cntrl_')
829 if cntrl.GetValueAsUnsigned(0):
830 self.cntrl = cntrl.Dereference()
834 # we can use two different categories for old and new formatters - type names are different enough that we should make no confusion
835 # talking with libc++ developer: "std::__1::class_name is set in stone
836 # until we decide to change the ABI. That shouldn't happen within a 5 year
840 def __lldb_init_module(debugger, dict):
841 debugger.HandleCommand(
842 'type summary add -F libcxx.stdstring_SummaryProvider "std::__1::string" -w libcxx')
843 debugger.HandleCommand(
844 'type summary add -F libcxx.stdstring_SummaryProvider "std::__1::basic_string<char, class std::__1::char_traits<char>, class std::__1::allocator<char> >" -w libcxx')
845 debugger.HandleCommand(
846 'type synthetic add -l libcxx.stdvector_SynthProvider -x "^(std::__1::)vector<.+>$" -w libcxx')
847 debugger.HandleCommand(
848 'type summary add -F libcxx.stdvector_SummaryProvider -e -x "^(std::__1::)vector<.+>$" -w libcxx')
849 debugger.HandleCommand(
850 'type synthetic add -l libcxx.stdlist_SynthProvider -x "^(std::__1::)list<.+>$" -w libcxx')
851 debugger.HandleCommand(
852 'type summary add -F libcxx.stdlist_SummaryProvider -e -x "^(std::__1::)list<.+>$" -w libcxx')
853 debugger.HandleCommand(
854 'type synthetic add -l libcxx.stdmap_SynthProvider -x "^(std::__1::)map<.+> >$" -w libcxx')
855 debugger.HandleCommand(
856 'type summary add -F libcxx.stdmap_SummaryProvider -e -x "^(std::__1::)map<.+> >$" -w libcxx')
857 debugger.HandleCommand("type category enable libcxx")
858 debugger.HandleCommand(
859 'type synthetic add -l libcxx.stddeque_SynthProvider -x "^(std::__1::)deque<.+>$" -w libcxx')
860 debugger.HandleCommand(
861 'type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)shared_ptr<.+>$" -w libcxx')
862 # turns out the structs look the same, so weak_ptr can be handled the same!
863 debugger.HandleCommand(
864 'type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)weak_ptr<.+>$" -w libcxx')
866 _map_capping_size = 255
867 _list_capping_size = 255
868 _list_uses_loop_detector = True
869 _deque_capping_size = 255