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