xref: /llvm-project/lldb/examples/summaries/cocoa/CFBitVector.py (revision cfdafa37b4d3552268a92d7dfd107ed92d3dca51)
1# summary provider for CF(Mutable)BitVector
2import lldb
3import ctypes
4import objc_runtime
5import metrics
6
7# first define some utility functions
8def byte_index(abs_pos):
9	return abs_pos/8
10
11def bit_index(abs_pos):
12	return abs_pos & 7
13
14def get_bit(byte,index):
15	if index < 0 or index > 7:
16		return None
17	return (byte >> (7-index)) & 1
18
19def grab_array_item_data(pointer,index):
20	return pointer.GetPointeeData(index,1)
21
22statistics = metrics.Metrics()
23statistics.add_metric('invalid_isa')
24statistics.add_metric('invalid_pointer')
25statistics.add_metric('unknown_class')
26statistics.add_metric('code_notrun')
27
28# despite the similary to synthetic children providers, these classes are not
29# trying to provide anything but a summary for a CF*BitVector, so they need not
30# obey the interface specification for synthetic children providers
31class CFBitVectorKnown_SummaryProvider:
32	def adjust_for_architecture(self):
33		self.uiint_size = self.sys_params.types_cache.NSUInteger.GetByteSize()
34		pass
35
36	def __init__(self, valobj, params):
37		self.valobj = valobj;
38		self.sys_params = params
39		if not(self.sys_params.types_cache.NSUInteger):
40			if self.sys_params.is_64_bit:
41				self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
42			else:
43				self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
44		if not(self.sys_params.types_cache.charptr):
45			self.sys_params.types_cache.charptr = self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar).GetPointerType()
46		self.update();
47
48	def update(self):
49		self.adjust_for_architecture();
50
51	# we skip the CFRuntimeBase
52	# then the next CFIndex is the count
53	# then we skip another CFIndex and then we get at a byte array
54	# that wraps the individual bits
55
56	def contents(self):
57		count_vo = self.valobj.CreateChildAtOffset("count",self.sys_params.cfruntime_size,
58													self.sys_params.types_cache.NSUInteger)
59		count = count_vo.GetValueAsUnsigned(0)
60		if count == 0:
61			return '(empty)'
62
63		array_vo = self.valobj.CreateChildAtOffset("data",
64													self.sys_params.cfruntime_size+2*self.uiint_size,
65													self.sys_params.types_cache.charptr)
66
67		data_list = []
68		cur_byte_pos = None
69		for i in range(0,count):
70			if cur_byte_pos == None:
71				cur_byte_pos = byte_index(i)
72				cur_byte = grab_array_item_data(array_vo,cur_byte_pos)
73				cur_byte_val = cur_byte.uint8[0]
74			else:
75				byte_pos = byte_index(i)
76				# do not fetch the pointee data every single time through
77				if byte_pos != cur_byte_pos:
78					cur_byte_pos = byte_pos
79					cur_byte = grab_array_item_data(array_vo,cur_byte_pos)
80					cur_byte_val = cur_byte.uint8[0]
81			bit = get_bit(cur_byte_val,bit_index(i))
82			if (i % 4) == 0:
83				data_list.append(' ')
84			if bit == 1:
85				data_list.append('1')
86			else:
87				data_list.append('0')
88		return ''.join(data_list)
89
90
91class CFBitVectorUnknown_SummaryProvider:
92	def adjust_for_architecture(self):
93		pass
94
95	def __init__(self, valobj, params):
96		self.valobj = valobj;
97		self.sys_params = params
98		self.update();
99
100	def update(self):
101		self.adjust_for_architecture();
102
103	def contents(self):
104		return '*** unknown class *** very bad thing *** find out my name ***'
105
106
107def GetSummary_Impl(valobj):
108	global statistics
109	class_data = objc_runtime.ObjCRuntime(valobj)
110	if class_data.is_valid() == False:
111		statistics.metric_hit('invalid_pointer',valobj)
112		wrapper = None
113		return
114	class_data = class_data.read_class_data()
115	if class_data.is_valid() == False:
116		statistics.metric_hit('invalid_isa',valobj)
117		wrapper = None
118		return
119	if class_data.is_kvo():
120		class_data = class_data.get_superclass()
121	if class_data.is_valid() == False:
122		statistics.metric_hit('invalid_isa',valobj)
123		wrapper = None
124		return
125
126	name_string = class_data.class_name()
127	if name_string == '__NSCFType':
128		# CFBitVectorRef does not expose an actual NSWrapper type, so we have to check that this is
129		# an NSCFType and then check we are a pointer-to CFBitVectorRef
130		valobj_type = valobj.GetType()
131		if valobj_type.IsValid() and valobj_type.IsPointerType():
132			pointee_type = valobj_type.GetPointeeType()
133			if pointee_type.GetName() == '__CFBitVector' or pointee_type.GetName() == '__CFMutableBitVector':
134				wrapper = CFBitVectorKnown_SummaryProvider(valobj, class_data.sys_params)
135				statistics.metric_hit('code_notrun',valobj)
136			else:
137				wrapper = CFBitVectorUnknown_SummaryProvider(valobj)
138				print pointee_type.GetName()
139	else:
140		wrapper = CFBitVectorUnknown_SummaryProvider(valobj, class_data.sys_params)
141		print name_string
142		statistics.metric_hit('unknown_class',str(valobj) + " seen as " + name_string)
143	return wrapper;
144
145def CFBitVector_SummaryProvider (valobj,dict):
146	provider = GetSummary_Impl(valobj);
147	if provider != None:
148	    #try:
149	    summary = provider.contents();
150	    #except:
151	    #    summary = None
152	    if summary == None or summary == '':
153	        summary = 'no valid bitvector here'
154	    return summary
155	return ''
156
157def __lldb_init_module(debugger,dict):
158	debugger.HandleCommand("type summary add -F CFBitVector.CFBitVector_SummaryProvider CFBitVectorRef CFMutableBitVectorRef")
159