diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:26:05 +0000 | 
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-01-02 19:26:05 +0000 | 
| commit | 14f1b3e8826ce43b978db93a62d1166055db5394 (patch) | |
| tree | 0a00ad8d3498783fe0193f3b656bca17c4c8697d /examples/synthetic/libcxx.py | |
| parent | 4ee8c119c71a06dcad1e0fecc8c675e480e59337 (diff) | |
Notes
Diffstat (limited to 'examples/synthetic/libcxx.py')
| -rw-r--r-- | examples/synthetic/libcxx.py | 1240 | 
1 files changed, 661 insertions, 579 deletions
diff --git a/examples/synthetic/libcxx.py b/examples/synthetic/libcxx.py index 6623fea097c4..e6f8223e2dad 100644 --- a/examples/synthetic/libcxx.py +++ b/examples/synthetic/libcxx.py @@ -4,583 +4,633 @@ 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 +# 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 + '"' + + +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 +    return True if (value & 1) == 0 else False + +  def extract_short_size(value): -	return ((value >> 1) % 256) +    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 + '"' +# 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) +        # the NULL terminator must be accounted for +        size = size_vo.GetValueAsUnsigned(0) + 1 +        if size <= 1 or size is 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()) +    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 __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 _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 _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 _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 _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 -	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) -	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() +    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() +        # we convert the SBValue to an internal node object on entry +        self.node = stdlist_entry(node) + +    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 is not 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 + +    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 not _list_uses_loop_detector: +            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 is 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 _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 _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 _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 _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 _null_impl(self): +        logger = lldb.formatters.Logger.Logger() +        return self.value == 0 -	def __init__(self,node): -		logger = lldb.formatters.Logger.Logger() -		self.node = node +    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) +    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() +    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() +        # we convert the SBValue to an internal node object on entry +        self.node = stdmap_iterator_node(node) +        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 is not 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() is 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()) +    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 is 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 is None or self.data_size is 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 is 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 is not 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 is 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() +                    # make sure we have a valid offset for the next items +                    self.get_value_offset(current) +                    # 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 is 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") @@ -592,7 +642,9 @@ class stddeque_SynthProvider:          except:              self.block_size = -1              self.element_size = -1 -        logger.write("block_size=%d, element_size=%d" % (self.block_size, self.element_size)) +        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 @@ -605,7 +657,7 @@ class stddeque_SynthProvider:          #    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 +            self.block_size = 4096 / self.element_size          else:              self.block_size = 16 @@ -619,24 +671,25 @@ class stddeque_SynthProvider:      def has_children(self):          return True -    def get_child_index(self,name): +    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): +    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; +            return None          if index >= self.num_children(): -                return None; +            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)) +            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 @@ -656,23 +709,29 @@ class stddeque_SynthProvider:              # 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) +            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) +            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) +            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) +            total_rows, junk = divmod( +                map_endcap - map_first, self.pointer_size)              if junk:                  logger.write("endcap-first doesnt align correctly")                  return @@ -684,18 +743,21 @@ class stddeque_SynthProvider:              if junk:                  logger.write("begin-first doesnt align correctly")                  return -            if not start_row*self.block_size <= start < (start_row+1)*self.block_size: +            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: +                    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)) +            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 @@ -706,7 +768,9 @@ class stddeque_SynthProvider:              self.map_first = None              self.map_begin = None +  class stdsharedptr_SynthProvider: +      def __init__(self, valobj, d):          logger = lldb.formatters.Logger.Logger()          logger.write("init") @@ -725,39 +789,42 @@ class stdsharedptr_SynthProvider:      def has_children(self):          return True -    def get_child_index(self,name): -        if name=="__ptr_": +    def get_child_index(self, name): +        if name == "__ptr_":              return 0 -        if name=="count": +        if name == "count":              return 1 -        if name=="weak_count": +        if name == "weak_count":              return 2          return -1 -    def get_child_at_index(self,index): +    def get_child_at_index(self, index):          if index == 0:              return self.ptr          if index == 1: -            if self.cntrl == None: +            if self.cntrl is 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) +                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: +            if self.cntrl is 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) +                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) +        self.ptr = self.valobj.GetChildMemberWithName( +            '__ptr_')  # .Cast(self.element_ptr_type)          cntrl = self.valobj.GetChildMemberWithName('__cntrl_')          if cntrl.GetValueAsUnsigned(0):              self.cntrl = cntrl.Dereference() @@ -765,21 +832,36 @@ class stdsharedptr_SynthProvider:              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') +# 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  | 
