diff options
Diffstat (limited to 'examples/synthetic/libcxx.py')
-rw-r--r-- | examples/synthetic/libcxx.py | 787 |
1 files changed, 787 insertions, 0 deletions
diff --git a/examples/synthetic/libcxx.py b/examples/synthetic/libcxx.py new file mode 100644 index 0000000000000..6623fea097c40 --- /dev/null +++ b/examples/synthetic/libcxx.py @@ -0,0 +1,787 @@ +import lldb +import lldb.formatters.Logger + +# libcxx STL formatters for LLDB +# These formatters are based upon the implementation of libc++ that +# ships with current releases of OS X - They will not work for other implementations +# of the standard C++ library - and they are bound to use the libc++-specific namespace + +# the std::string summary is just an example for your convenience +# the actual summary that LLDB uses is C++ code inside the debugger's own core + +# this could probably be made more efficient but since it only reads a handful of bytes at a time +# we probably don't need to worry too much about this for the time being +def make_string(F,L): + strval = '' + G = F.GetData().uint8 + for X in range(L): + V = G[X] + if V == 0: + break + strval = strval + chr(V % 256) + return '"' + strval + '"' + +# if we ever care about big-endian, these two functions might need to change +def is_short_string(value): + return True if (value & 1) == 0 else False +def extract_short_size(value): + return ((value >> 1) % 256) + +# some of the members of libc++ std::string are anonymous or have internal names that convey +# no external significance - we access them by index since this saves a name lookup that would add +# no information for readers of the code, but when possible try to use meaningful variable names +def stdstring_SummaryProvider(valobj,dict): + logger = lldb.formatters.Logger.Logger() + r = valobj.GetChildAtIndex(0) + B = r.GetChildAtIndex(0) + first = B.GetChildAtIndex(0) + D = first.GetChildAtIndex(0) + l = D.GetChildAtIndex(0) + s = D.GetChildAtIndex(1) + D20 = s.GetChildAtIndex(0) + size_mode = D20.GetChildAtIndex(0).GetValueAsUnsigned(0) + if is_short_string(size_mode): + size = extract_short_size(size_mode) + return make_string(s.GetChildAtIndex(1),size) + else: + data_ptr = l.GetChildAtIndex(2) + size_vo = l.GetChildAtIndex(1) + size = size_vo.GetValueAsUnsigned(0)+1 # the NULL terminator must be accounted for + if size <= 1 or size == None: # should never be the case + return '""' + try: + data = data_ptr.GetPointeeData(0,size) + except: + return '""' + error = lldb.SBError() + strval = data.GetString(error,0) + if error.Fail(): + return '<error:' + error.GetCString() + '>' + else: + return '"' + strval + '"' + +class stdvector_SynthProvider: + + def __init__(self, valobj, dict): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj; + + def num_children(self): + logger = lldb.formatters.Logger.Logger() + try: + start_val = self.start.GetValueAsUnsigned(0) + finish_val = self.finish.GetValueAsUnsigned(0) + # Before a vector has been constructed, it will contain bad values + # so we really need to be careful about the length we return since + # uninitialized data can cause us to return a huge number. We need + # to also check for any of the start, finish or end of storage values + # being zero (NULL). If any are, then this vector has not been + # initialized yet and we should return zero + + # Make sure nothing is NULL + if start_val == 0 or finish_val == 0: + return 0 + # Make sure start is less than finish + if start_val >= finish_val: + return 0 + + num_children = (finish_val-start_val) + if (num_children % self.data_size) != 0: + return 0 + else: + num_children = num_children/self.data_size + return num_children + except: + return 0; + + def get_child_index(self,name): + logger = lldb.formatters.Logger.Logger() + try: + return int(name.lstrip('[').rstrip(']')) + except: + return -1 + + def get_child_at_index(self,index): + logger = lldb.formatters.Logger.Logger() + logger >> "Retrieving child " + str(index) + if index < 0: + return None; + if index >= self.num_children(): + return None; + try: + offset = index * self.data_size + return self.start.CreateChildAtOffset('['+str(index)+']',offset,self.data_type) + except: + return None + + def update(self): + logger = lldb.formatters.Logger.Logger() + try: + self.start = self.valobj.GetChildMemberWithName('__begin_') + self.finish = self.valobj.GetChildMemberWithName('__end_') + # the purpose of this field is unclear, but it is the only field whose type is clearly T* for a vector<T> + # if this ends up not being correct, we can use the APIs to get at template arguments + data_type_finder = self.valobj.GetChildMemberWithName('__end_cap_').GetChildMemberWithName('__first_') + self.data_type = data_type_finder.GetType().GetPointeeType() + self.data_size = self.data_type.GetByteSize() + except: + pass + + def has_children(self): + return True + +# Just an example: the actual summary is produced by a summary string: size=${svar%#} +def stdvector_SummaryProvider(valobj,dict): + prov = stdvector_SynthProvider(valobj,None) + return 'size=' + str(prov.num_children()) + +class stdlist_entry: + + def __init__(self,entry): + logger = lldb.formatters.Logger.Logger() + self.entry = entry + + def _next_impl(self): + logger = lldb.formatters.Logger.Logger() + return stdlist_entry(self.entry.GetChildMemberWithName('__next_')) + + def _prev_impl(self): + logger = lldb.formatters.Logger.Logger() + return stdlist_entry(self.entry.GetChildMemberWithName('__prev_')) + + def _value_impl(self): + logger = lldb.formatters.Logger.Logger() + return self.entry.GetValueAsUnsigned(0) + + def _isnull_impl(self): + logger = lldb.formatters.Logger.Logger() + return self._value_impl() == 0 + + def _sbvalue_impl(self): + logger = lldb.formatters.Logger.Logger() + return self.entry + + next = property(_next_impl,None) + value = property(_value_impl,None) + is_null = property(_isnull_impl,None) + sbvalue = property(_sbvalue_impl,None) + +class stdlist_iterator: + + def increment_node(self,node): + logger = lldb.formatters.Logger.Logger() + if node.is_null: + return None + return node.next + + def __init__(self,node): + logger = lldb.formatters.Logger.Logger() + self.node = stdlist_entry(node) # we convert the SBValue to an internal node object on entry + + def value(self): + logger = lldb.formatters.Logger.Logger() + return self.node.sbvalue # and return the SBValue back on exit + + def next(self): + logger = lldb.formatters.Logger.Logger() + node = self.increment_node(self.node) + if node != None and node.sbvalue.IsValid() and not(node.is_null): + self.node = node + return self.value() + else: + return None + + def advance(self,N): + logger = lldb.formatters.Logger.Logger() + if N < 0: + return None + if N == 0: + return self.value() + if N == 1: + return self.next() + while N > 0: + self.next() + N = N - 1 + return self.value() + + +class stdlist_SynthProvider: + def __init__(self, valobj, dict): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj + self.count = None + + def next_node(self,node): + logger = lldb.formatters.Logger.Logger() + return node.GetChildMemberWithName('__next_') + + def value(self,node): + logger = lldb.formatters.Logger.Logger() + return node.GetValueAsUnsigned() + + # Floyd's cycle-finding algorithm + # try to detect if this list has a loop + def has_loop(self): + global _list_uses_loop_detector + logger = lldb.formatters.Logger.Logger() + if _list_uses_loop_detector == False: + logger >> "Asked not to use loop detection" + return False + slow = stdlist_entry(self.head) + fast1 = stdlist_entry(self.head) + fast2 = stdlist_entry(self.head) + while slow.next.value != self.node_address: + slow_value = slow.value + fast1 = fast2.next + fast2 = fast1.next + if fast1.value == slow_value or fast2.value == slow_value: + return True + slow = slow.next + return False + + def num_children(self): + global _list_capping_size + logger = lldb.formatters.Logger.Logger() + if self.count == None: + self.count = self.num_children_impl() + if self.count > _list_capping_size: + self.count = _list_capping_size + return self.count + + def num_children_impl(self): + global _list_capping_size + logger = lldb.formatters.Logger.Logger() + try: + next_val = self.head.GetValueAsUnsigned(0) + prev_val = self.tail.GetValueAsUnsigned(0) + # After a std::list has been initialized, both next and prev will be non-NULL + if next_val == 0 or prev_val == 0: + return 0 + if next_val == self.node_address: + return 0 + if next_val == prev_val: + return 1 + if self.has_loop(): + return 0 + size = 2 + current = stdlist_entry(self.head) + while current.next.value != self.node_address: + size = size + 1 + current = current.next + if size > _list_capping_size: + return _list_capping_size + return (size - 1) + except: + return 0; + + def get_child_index(self,name): + logger = lldb.formatters.Logger.Logger() + try: + return int(name.lstrip('[').rstrip(']')) + except: + return -1 + + def get_child_at_index(self,index): + logger = lldb.formatters.Logger.Logger() + logger >> "Fetching child " + str(index) + if index < 0: + return None; + if index >= self.num_children(): + return None; + try: + current = stdlist_iterator(self.head) + current = current.advance(index) + # we do not return __value_ because then all our children would be named __value_ + # we need to make a copy of __value__ with the right name - unfortunate + obj = current.GetChildMemberWithName('__value_') + obj_data = obj.GetData() + return self.valobj.CreateValueFromData('[' + str(index) + ']',obj_data,self.data_type) + except: + return None + + def extract_type(self): + logger = lldb.formatters.Logger.Logger() + list_type = self.valobj.GetType().GetUnqualifiedType() + if list_type.IsReferenceType(): + list_type = list_type.GetDereferencedType() + if list_type.GetNumberOfTemplateArguments() > 0: + data_type = list_type.GetTemplateArgumentType(0) + else: + data_type = None + return data_type + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.count = None + try: + impl = self.valobj.GetChildMemberWithName('__end_') + self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0) + self.head = impl.GetChildMemberWithName('__next_') + self.tail = impl.GetChildMemberWithName('__prev_') + self.data_type = self.extract_type() + self.data_size = self.data_type.GetByteSize() + except: + pass + + def has_children(self): + return True + + +# Just an example: the actual summary is produced by a summary string: size=${svar%#} +def stdlist_SummaryProvider(valobj,dict): + prov = stdlist_SynthProvider(valobj,None) + return 'size=' + str(prov.num_children()) + +# a tree node - this class makes the syntax in the actual iterator nicer to read and maintain +class stdmap_iterator_node: + def _left_impl(self): + logger = lldb.formatters.Logger.Logger() + return stdmap_iterator_node(self.node.GetChildMemberWithName("__left_")) + + def _right_impl(self): + logger = lldb.formatters.Logger.Logger() + return stdmap_iterator_node(self.node.GetChildMemberWithName("__right_")) + + def _parent_impl(self): + logger = lldb.formatters.Logger.Logger() + return stdmap_iterator_node(self.node.GetChildMemberWithName("__parent_")) + + def _value_impl(self): + logger = lldb.formatters.Logger.Logger() + return self.node.GetValueAsUnsigned(0) + + def _sbvalue_impl(self): + logger = lldb.formatters.Logger.Logger() + return self.node + + def _null_impl(self): + logger = lldb.formatters.Logger.Logger() + return self.value == 0 + + def __init__(self,node): + logger = lldb.formatters.Logger.Logger() + self.node = node + + left = property(_left_impl,None) + right = property(_right_impl,None) + parent = property(_parent_impl,None) + value = property(_value_impl,None) + is_null = property(_null_impl,None) + sbvalue = property(_sbvalue_impl,None) + +# a Python implementation of the tree iterator used by libc++ +class stdmap_iterator: + + def tree_min(self,x): + logger = lldb.formatters.Logger.Logger() + steps = 0 + if x.is_null: + return None + while (not x.left.is_null): + x = x.left + steps += 1 + if steps > self.max_count: + logger >> "Returning None - we overflowed" + return None + return x + + def tree_max(self,x): + logger = lldb.formatters.Logger.Logger() + if x.is_null: + return None + while (not x.right.is_null): + x = x.right + return x + + def tree_is_left_child(self,x): + logger = lldb.formatters.Logger.Logger() + if x.is_null: + return None + return True if x.value == x.parent.left.value else False + + def increment_node(self,node): + logger = lldb.formatters.Logger.Logger() + if node.is_null: + return None + if not node.right.is_null: + return self.tree_min(node.right) + steps = 0 + while (not self.tree_is_left_child(node)): + steps += 1 + if steps > self.max_count: + logger >> "Returning None - we overflowed" + return None + node = node.parent + return node.parent + + def __init__(self,node,max_count=0): + logger = lldb.formatters.Logger.Logger() + self.node = stdmap_iterator_node(node) # we convert the SBValue to an internal node object on entry + self.max_count = max_count + + def value(self): + logger = lldb.formatters.Logger.Logger() + return self.node.sbvalue # and return the SBValue back on exit + + def next(self): + logger = lldb.formatters.Logger.Logger() + node = self.increment_node(self.node) + if node != None and node.sbvalue.IsValid() and not(node.is_null): + self.node = node + return self.value() + else: + return None + + def advance(self,N): + logger = lldb.formatters.Logger.Logger() + if N < 0: + return None + if N == 0: + return self.value() + if N == 1: + return self.next() + while N > 0: + if self.next() == None: + return None + N = N - 1 + return self.value() + +class stdmap_SynthProvider: + + def __init__(self, valobj, dict): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj; + self.pointer_size = self.valobj.GetProcess().GetAddressByteSize() + self.count = None + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.count = None + try: + # 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 + # if this gets set to True, then we will merrily return None for any child from that moment on + self.garbage = False + self.tree = self.valobj.GetChildMemberWithName('__tree_') + self.root_node = self.tree.GetChildMemberWithName('__begin_node_') + # this data is either lazily-calculated, or cannot be inferred at this moment + # we still need to mark it as None, meaning "please set me ASAP" + self.data_type = None + self.data_size = None + self.skip_size = None + except: + pass + + def num_children(self): + global _map_capping_size + logger = lldb.formatters.Logger.Logger() + if self.count == None: + self.count = self.num_children_impl() + if self.count > _map_capping_size: + self.count = _map_capping_size + return self.count + + def num_children_impl(self): + logger = lldb.formatters.Logger.Logger() + try: + return self.valobj.GetChildMemberWithName('__tree_').GetChildMemberWithName('__pair3_').GetChildMemberWithName('__first_').GetValueAsUnsigned() + except: + return 0; + + def has_children(self): + return True + + def get_data_type(self): + logger = lldb.formatters.Logger.Logger() + if self.data_type == None or self.data_size == None: + if self.num_children() == 0: + return False + deref = self.root_node.Dereference() + if not(deref.IsValid()): + return False + value = deref.GetChildMemberWithName('__value_') + if not(value.IsValid()): + return False + self.data_type = value.GetType() + self.data_size = self.data_type.GetByteSize() + self.skip_size = None + return True + else: + return True + + def get_value_offset(self,node): + logger = lldb.formatters.Logger.Logger() + if self.skip_size == None: + node_type = node.GetType() + fields_count = node_type.GetNumberOfFields() + for i in range(fields_count): + field = node_type.GetFieldAtIndex(i) + if field.GetName() == '__value_': + self.skip_size = field.GetOffsetInBytes() + break + return (self.skip_size != None) + + def get_child_index(self,name): + logger = lldb.formatters.Logger.Logger() + try: + return int(name.lstrip('[').rstrip(']')) + except: + return -1 + + def get_child_at_index(self,index): + logger = lldb.formatters.Logger.Logger() + logger >> "Retrieving child " + str(index) + if index < 0: + return None + if index >= self.num_children(): + return None; + if self.garbage: + logger >> "Returning None since this tree is garbage" + return None + try: + iterator = stdmap_iterator(self.root_node,max_count=self.num_children()) + # the debug info for libc++ std::map is such that __begin_node_ has a very nice and useful type + # out of which we can grab the information we need - every other node has a less informative + # type which omits all value information and only contains housekeeping information for the RB tree + # hence, we need to know if we are at a node != 0, so that we can still get at the data + need_to_skip = (index > 0) + current = iterator.advance(index) + if current == None: + logger >> "Tree is garbage - returning None" + self.garbage = True + return None + if self.get_data_type(): + if not(need_to_skip): + current = current.Dereference() + obj = current.GetChildMemberWithName('__value_') + obj_data = obj.GetData() + self.get_value_offset(current) # make sure we have a valid offset for the next items + # we do not return __value_ because then we would end up with a child named + # __value_ instead of [0] + return self.valobj.CreateValueFromData('[' + str(index) + ']',obj_data,self.data_type) + else: + # FIXME we need to have accessed item 0 before accessing any other item! + if self.skip_size == None: + logger >> "You asked for item > 0 before asking for item == 0, I will fetch 0 now then retry" + if self.get_child_at_index(0): + return self.get_child_at_index(index) + else: + logger >> "item == 0 could not be found. sorry, nothing can be done here." + return None + return current.CreateChildAtOffset('[' + str(index) + ']',self.skip_size,self.data_type) + else: + logger >> "Unable to infer data-type - returning None (should mark tree as garbage here?)" + return None + except Exception as err: + logger >> "Hit an exception: " + str(err) + return None + +# Just an example: the actual summary is produced by a summary string: size=${svar%#} +def stdmap_SummaryProvider(valobj,dict): + prov = stdmap_SynthProvider(valobj,None) + return 'size=' + str(prov.num_children()) + +class stddeque_SynthProvider: + def __init__(self, valobj, d): + logger = lldb.formatters.Logger.Logger() + logger.write("init") + self.valobj = valobj + self.pointer_size = self.valobj.GetProcess().GetAddressByteSize() + self.count = None + try: + self.find_block_size() + except: + self.block_size = -1 + self.element_size = -1 + logger.write("block_size=%d, element_size=%d" % (self.block_size, self.element_size)) + + def find_block_size(self): + # in order to use the deque we must have the block size, or else + # it's impossible to know what memory addresses are valid + self.element_type = self.valobj.GetType().GetTemplateArgumentType(0) + self.element_size = self.element_type.GetByteSize() + # The code says this, but there must be a better way: + # template <class _Tp, class _Allocator> + # class __deque_base { + # static const difference_type __block_size = sizeof(value_type) < 256 ? 4096 / sizeof(value_type) : 16; + # } + if self.element_size < 256: + self.block_size = 4096 / self.element_size + else: + self.block_size = 16 + + def num_children(self): + global _deque_capping_size + logger = lldb.formatters.Logger.Logger() + if self.count is None: + return 0 + return min(self.count, _deque_capping_size) + + def has_children(self): + return True + + def get_child_index(self,name): + logger = lldb.formatters.Logger.Logger() + try: + return int(name.lstrip('[').rstrip(']')) + except: + return -1 + + def get_child_at_index(self,index): + logger = lldb.formatters.Logger.Logger() + logger.write("Fetching child " + str(index)) + if index < 0 or self.count is None: + return None; + if index >= self.num_children(): + return None; + try: + i, j = divmod(self.start+index, self.block_size) + return self.first.CreateValueFromExpression('[' + str(index) + ']', + '*(*(%s + %d) + %d)' % (self.first.get_expr_path(), i, j)) + except: + return None + + def update(self): + logger = lldb.formatters.Logger.Logger() + try: + # A deque is effectively a two-dim array, with fixed width. + # 'map' contains pointers to the rows of this array. The + # full memory area allocated by the deque is delimited + # by 'first' and 'end_cap'. However, only a subset of this + # memory contains valid data since a deque may have some slack + # at the front and back in order to have O(1) insertion at + # both ends. The rows in active use are delimited by + # 'begin' and 'end'. + # + # To find the elements that are actually constructed, the 'start' + # variable tells which element in this NxM array is the 0th + # one, and the 'size' element gives the number of elements + # in the deque. + count = self.valobj.GetChildMemberWithName('__size_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) + # give up now if we cant access memory reliably + if self.block_size < 0: + logger.write("block_size < 0") + return + map_ = self.valobj.GetChildMemberWithName('__map_') + start = self.valobj.GetChildMemberWithName('__start_').GetValueAsUnsigned(0) + first = map_.GetChildMemberWithName('__first_') + map_first = first.GetValueAsUnsigned(0) + map_begin = map_.GetChildMemberWithName('__begin_').GetValueAsUnsigned(0) + map_end = map_.GetChildMemberWithName('__end_').GetValueAsUnsigned(0) + map_endcap= map_.GetChildMemberWithName('__end_cap_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) + # check consistency + if not map_first <= map_begin <= map_end <= map_endcap: + logger.write("map pointers are not monotonic") + return + total_rows, junk = divmod(map_endcap - map_first, self.pointer_size) + if junk: + logger.write("endcap-first doesnt align correctly") + return + active_rows, junk = divmod(map_end - map_begin, self.pointer_size) + if junk: + logger.write("end-begin doesnt align correctly") + return + start_row, junk = divmod(map_begin - map_first, self.pointer_size) + if junk: + logger.write("begin-first doesnt align correctly") + return + if not start_row*self.block_size <= start < (start_row+1)*self.block_size: + logger.write("0th element must be in the 'begin' row") + return + end_row = start_row + active_rows + if not count: + if active_rows: + logger.write("empty deque but begin!=end") + return + elif not (end_row-1)*self.block_size <= start+count < end_row*self.block_size: + logger.write("nth element must be before the 'end' row") + return + logger.write("update success: count=%r, start=%r, first=%r" % (count,start,first)) + # if consistent, save all we really need: + self.count = count + self.start = start + self.first = first + except: + self.count = None + self.start = None + self.map_first = None + self.map_begin = None + +class stdsharedptr_SynthProvider: + def __init__(self, valobj, d): + logger = lldb.formatters.Logger.Logger() + logger.write("init") + self.valobj = valobj + #self.element_ptr_type = self.valobj.GetType().GetTemplateArgumentType(0).GetPointerType() + self.ptr = None + self.cntrl = None + process = valobj.GetProcess() + self.endianness = process.GetByteOrder() + self.pointer_size = process.GetAddressByteSize() + self.count_type = valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) + + def num_children(self): + return 1 + + def has_children(self): + return True + + def get_child_index(self,name): + if name=="__ptr_": + return 0 + if name=="count": + return 1 + if name=="weak_count": + return 2 + return -1 + + def get_child_at_index(self,index): + if index == 0: + return self.ptr + if index == 1: + if self.cntrl == None: + count = 0 + else: + count = 1 + self.cntrl.GetChildMemberWithName('__shared_owners_').GetValueAsSigned() + return self.valobj.CreateValueFromData("count", + lldb.SBData.CreateDataFromUInt64Array(self.endianness, self.pointer_size, [count]), + self.count_type) + if index == 2: + if self.cntrl == None: + count = 0 + else: + count = 1 + self.cntrl.GetChildMemberWithName('__shared_weak_owners_').GetValueAsSigned() + return self.valobj.CreateValueFromData("weak_count", + lldb.SBData.CreateDataFromUInt64Array(self.endianness, self.pointer_size, [count]), + self.count_type) + return None + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.ptr = self.valobj.GetChildMemberWithName('__ptr_')#.Cast(self.element_ptr_type) + cntrl = self.valobj.GetChildMemberWithName('__cntrl_') + if cntrl.GetValueAsUnsigned(0): + self.cntrl = cntrl.Dereference() + else: + self.cntrl = None + +# we can use two different categories for old and new formatters - type names are different enough that we should make no confusion +# talking with libc++ developer: "std::__1::class_name is set in stone until we decide to change the ABI. That shouldn't happen within a 5 year time frame" +def __lldb_init_module(debugger,dict): + debugger.HandleCommand('type summary add -F libcxx.stdstring_SummaryProvider "std::__1::string" -w libcxx') + debugger.HandleCommand('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') + debugger.HandleCommand('type synthetic add -l libcxx.stdvector_SynthProvider -x "^(std::__1::)vector<.+>$" -w libcxx') + debugger.HandleCommand('type summary add -F libcxx.stdvector_SummaryProvider -e -x "^(std::__1::)vector<.+>$" -w libcxx') + debugger.HandleCommand('type synthetic add -l libcxx.stdlist_SynthProvider -x "^(std::__1::)list<.+>$" -w libcxx') + debugger.HandleCommand('type summary add -F libcxx.stdlist_SummaryProvider -e -x "^(std::__1::)list<.+>$" -w libcxx') + debugger.HandleCommand('type synthetic add -l libcxx.stdmap_SynthProvider -x "^(std::__1::)map<.+> >$" -w libcxx') + debugger.HandleCommand('type summary add -F libcxx.stdmap_SummaryProvider -e -x "^(std::__1::)map<.+> >$" -w libcxx') + debugger.HandleCommand("type category enable libcxx") + debugger.HandleCommand('type synthetic add -l libcxx.stddeque_SynthProvider -x "^(std::__1::)deque<.+>$" -w libcxx') + debugger.HandleCommand('type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)shared_ptr<.+>$" -w libcxx') + # turns out the structs look the same, so weak_ptr can be handled the same! + debugger.HandleCommand('type synthetic add -l libcxx.stdsharedptr_SynthProvider -x "^(std::__1::)weak_ptr<.+>$" -w libcxx') + +_map_capping_size = 255 +_list_capping_size = 255 +_list_uses_loop_detector = True +_deque_capping_size = 255 |