xref: /llvm-project/lldb/examples/summaries/cocoa/CFArray.py (revision cfdafa37b4d3552268a92d7dfd107ed92d3dca51)
1# synthetic children provider for NSArray
2import lldb
3import ctypes
4import objc_runtime
5import metrics
6
7statistics = metrics.Metrics()
8statistics.add_metric('invalid_isa')
9statistics.add_metric('invalid_pointer')
10statistics.add_metric('unknown_class')
11statistics.add_metric('code_notrun')
12
13# much less functional than the other two cases below
14# just runs code to get to the count and then returns
15# no children
16class NSArrayKVC_SynthProvider:
17
18	def adjust_for_architecture(self):
19		pass
20
21	def __init__(self, valobj, dict, params):
22		self.valobj = valobj;
23		self.update()
24
25	def update(self):
26		self.adjust_for_architecture();
27
28	def num_children(self):
29		stream = lldb.SBStream()
30		self.valobj.GetExpressionPath(stream)
31		num_children_vo = self.valobj.CreateValueFromExpression("count","(int)[" + stream.GetData() + " count]");
32		return num_children_vo.GetValueAsUnsigned(0)
33
34# much less functional than the other two cases below
35# just runs code to get to the count and then returns
36# no children
37class NSArrayCF_SynthProvider:
38
39	def adjust_for_architecture(self):
40		pass
41
42	def __init__(self, valobj, dict, params):
43		self.valobj = valobj;
44		self.sys_params = params
45		if not (self.sys_params.types_cache.ulong):
46			self.sys_params.types_cache.ulong = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
47		self.update()
48
49	def update(self):
50		self.adjust_for_architecture();
51
52	def num_children(self):
53		num_children_vo = self.valobj.CreateChildAtOffset("count",
54							self.sys_params.cfruntime_size,
55							self.sys_params.types_cache.ulong)
56		return num_children_vo.GetValueAsUnsigned(0)
57
58class NSArrayI_SynthProvider:
59	def adjust_for_architecture(self):
60		pass
61
62	def __init__(self, valobj, dict, params):
63		self.valobj = valobj;
64		self.sys_params = params
65		if not(self.sys_params.types_cache.long):
66			self.sys_params.types_cache.long = self.valobj.GetType().GetBasicType(lldb.eBasicTypeLong)
67		self.update()
68
69	def update(self):
70		self.adjust_for_architecture();
71
72	# skip the isa pointer and get at the size
73	def num_children(self):
74		count = self.valobj.CreateChildAtOffset("count",
75				self.sys_params.pointer_size,
76				self.sys_params.types_cache.long);
77		return count.GetValueAsUnsigned(0)
78
79class NSArrayM_SynthProvider:
80	def adjust_for_architecture(self):
81		pass
82
83	def __init__(self, valobj, dict, params):
84		self.valobj = valobj;
85		self.sys_params = params
86		if not(self.sys_params.types_cache.long):
87			self.sys_params.types_cache.long = self.valobj.GetType().GetBasicType(lldb.eBasicTypeLong)
88		self.update()
89
90	def update(self):
91		self.adjust_for_architecture();
92
93	# skip the isa pointer and get at the size
94	def num_children(self):
95		count = self.valobj.CreateChildAtOffset("count",
96				self.sys_params.pointer_size,
97				self.sys_params.types_cache.long);
98		return count.GetValueAsUnsigned(0)
99
100# this is the actual synth provider, but is just a wrapper that checks
101# whether valobj is an instance of __NSArrayI or __NSArrayM and sets up an
102# appropriate backend layer to do the computations
103class NSArray_SynthProvider:
104	def adjust_for_architecture(self):
105		pass
106
107	def __init__(self, valobj, dict):
108		self.valobj = valobj;
109		self.adjust_for_architecture()
110		self.wrapper = self.make_wrapper(valobj,dict)
111		self.invalid = (self.wrapper == None)
112
113	def num_children(self):
114		if self.wrapper == None:
115			return 0;
116		return self.wrapper.num_children()
117
118	def update(self):
119		if self.wrapper == None:
120			return
121		self.wrapper.update()
122
123	# this code acts as our defense against NULL and unitialized
124	# NSArray pointers, which makes it much longer than it would be otherwise
125	def make_wrapper(self,valobj,dict):
126		global statistics
127		class_data = objc_runtime.ObjCRuntime(valobj)
128		if class_data.is_valid() == False:
129			statistics.metric_hit('invalid_pointer',valobj)
130			wrapper = None
131			return
132		class_data = class_data.read_class_data()
133		if class_data.is_valid() == False:
134			statistics.metric_hit('invalid_isa',valobj)
135			wrapper = None
136			return
137		if class_data.is_kvo():
138			class_data = class_data.get_superclass()
139		if class_data.is_valid() == False:
140			statistics.metric_hit('invalid_isa',valobj)
141			wrapper = None
142			return
143
144		name_string = class_data.class_name()
145		if name_string == '__NSArrayI':
146			wrapper = NSArrayI_SynthProvider(valobj, dict, class_data.sys_params)
147			statistics.metric_hit('code_notrun',valobj)
148		elif name_string == '__NSArrayM':
149			wrapper = NSArrayM_SynthProvider(valobj, dict, class_data.sys_params)
150			statistics.metric_hit('code_notrun',valobj)
151		elif name_string == '__NSCFArray':
152			wrapper = NSArrayCF_SynthProvider(valobj, dict, class_data.sys_params)
153			statistics.metric_hit('code_notrun',valobj)
154		else:
155			wrapper = NSArrayKVC_SynthProvider(valobj, dict, class_data.sys_params)
156			statistics.metric_hit('unknown_class',str(valobj) + " seen as " + name_string)
157		return wrapper;
158
159def CFArray_SummaryProvider (valobj,dict):
160	provider = NSArray_SynthProvider(valobj,dict);
161	if provider.invalid == False:
162	    try:
163	        summary = str(provider.num_children());
164	    except:
165	        summary = None
166	    if summary == None:
167	        summary = 'no valid array here'
168	    return summary + " objects"
169	return ''
170
171def __lldb_init_module(debugger,dict):
172	debugger.HandleCommand("type summary add -F CFArray.CFArray_SummaryProvider NSArray CFArrayRef CFMutableArrayRef")
173