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 000000000000..6623fea097c4 --- /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 | 
