blob: a6c7768671aae8f06317266b2ea841b07ea915e4 [file] [log] [blame]
Enrico Granata3f1052b2012-03-13 21:52:00 +00001"""
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"""
Enrico Granataeb4a4792012-02-23 23:10:27 +00008# summary provider for NSSet
9import lldb
10import ctypes
Enrico Granata28399ad2012-04-25 01:39:27 +000011import lldb.runtime.objc.objc_runtime
12import lldb.formatters.metrics
Enrico Granata896cd1d2012-03-01 19:32:33 +000013import CFBag
Enrico Granata28399ad2012-04-25 01:39:27 +000014import lldb.formatters.Logger
Enrico Granataeb4a4792012-02-23 23:10:27 +000015
Enrico Granata28399ad2012-04-25 01:39:27 +000016statistics = lldb.formatters.metrics.Metrics()
Enrico Granataeb4a4792012-02-23 23:10:27 +000017statistics.add_metric('invalid_isa')
18statistics.add_metric('invalid_pointer')
19statistics.add_metric('unknown_class')
20statistics.add_metric('code_notrun')
21
22# despite the similary to synthetic children providers, these classes are not
23# trying to provide anything but the port number of an NSMachPort, so they need not
24# obey the interface specification for synthetic children providers
Kate Stoneb9c1b512016-09-06 20:57:50 +000025
26
Enrico Granataeb4a4792012-02-23 23:10:27 +000027class NSCFSet_SummaryProvider:
Enrico Granataeb4a4792012-02-23 23:10:27 +000028
Kate Stoneb9c1b512016-09-06 20:57:50 +000029 def adjust_for_architecture(self):
30 pass
Enrico Granataeb4a4792012-02-23 23:10:27 +000031
Kate Stoneb9c1b512016-09-06 20:57:50 +000032 def __init__(self, valobj, params):
33 logger = lldb.formatters.Logger.Logger()
34 self.valobj = valobj
35 self.sys_params = params
36 if not(self.sys_params.types_cache.NSUInteger):
37 if self.sys_params.is_64_bit:
38 self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
39 ).GetBasicType(lldb.eBasicTypeUnsignedLong)
40 else:
41 self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
42 ).GetBasicType(lldb.eBasicTypeUnsignedInt)
43 self.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +000044
Kate Stoneb9c1b512016-09-06 20:57:50 +000045 def update(self):
46 logger = lldb.formatters.Logger.Logger()
47 self.adjust_for_architecture()
Enrico Granataeb4a4792012-02-23 23:10:27 +000048
Kate Stoneb9c1b512016-09-06 20:57:50 +000049 # one pointer is the ISA
50 # then we have one other internal pointer, plus
51 # 4 bytes worth of flags. hence, these values
52 def offset(self):
53 logger = lldb.formatters.Logger.Logger()
54 if self.sys_params.is_64_bit:
55 return 20
56 else:
57 return 12
58
59 def count(self):
60 logger = lldb.formatters.Logger.Logger()
61 vcount = self.valobj.CreateChildAtOffset(
62 "count", self.offset(), self.sys_params.types_cache.NSUInteger)
63 return vcount.GetValueAsUnsigned(0)
Enrico Granataeb4a4792012-02-23 23:10:27 +000064
65
66class NSSetUnknown_SummaryProvider:
Enrico Granataeb4a4792012-02-23 23:10:27 +000067
Kate Stoneb9c1b512016-09-06 20:57:50 +000068 def adjust_for_architecture(self):
69 pass
Enrico Granataeb4a4792012-02-23 23:10:27 +000070
Kate Stoneb9c1b512016-09-06 20:57:50 +000071 def __init__(self, valobj, params):
72 logger = lldb.formatters.Logger.Logger()
73 self.valobj = valobj
74 self.sys_params = params
75 self.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +000076
Kate Stoneb9c1b512016-09-06 20:57:50 +000077 def update(self):
78 logger = lldb.formatters.Logger.Logger()
79 self.adjust_for_architecture()
80
81 def count(self):
82 logger = lldb.formatters.Logger.Logger()
83 stream = lldb.SBStream()
84 self.valobj.GetExpressionPath(stream)
85 expr = "(int)[" + stream.GetData() + " count]"
86 num_children_vo = self.valobj.CreateValueFromExpression("count", expr)
87 if num_children_vo.IsValid():
88 return num_children_vo.GetValueAsUnsigned(0)
89 return '<variable is not NSSet>'
90
Enrico Granataeb4a4792012-02-23 23:10:27 +000091
92class NSSetI_SummaryProvider:
Enrico Granataeb4a4792012-02-23 23:10:27 +000093
Kate Stoneb9c1b512016-09-06 20:57:50 +000094 def adjust_for_architecture(self):
95 pass
Enrico Granataeb4a4792012-02-23 23:10:27 +000096
Kate Stoneb9c1b512016-09-06 20:57:50 +000097 def __init__(self, valobj, params):
98 logger = lldb.formatters.Logger.Logger()
99 self.valobj = valobj
100 self.sys_params = params
101 if not(self.sys_params.types_cache.NSUInteger):
102 if self.sys_params.is_64_bit:
103 self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
104 ).GetBasicType(lldb.eBasicTypeUnsignedLong)
105 else:
106 self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
107 ).GetBasicType(lldb.eBasicTypeUnsignedInt)
108 self.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +0000109
Kate Stoneb9c1b512016-09-06 20:57:50 +0000110 def update(self):
111 logger = lldb.formatters.Logger.Logger()
112 self.adjust_for_architecture()
Enrico Granataeb4a4792012-02-23 23:10:27 +0000113
Kate Stoneb9c1b512016-09-06 20:57:50 +0000114 # we just need to skip the ISA and the count immediately follows
115 def offset(self):
116 logger = lldb.formatters.Logger.Logger()
117 return self.sys_params.pointer_size
118
119 def count(self):
120 logger = lldb.formatters.Logger.Logger()
121 num_children_vo = self.valobj.CreateChildAtOffset(
122 "count", self.offset(), self.sys_params.types_cache.NSUInteger)
123 value = num_children_vo.GetValueAsUnsigned(0)
124 if value is not None:
125 # the MSB on immutable sets seems to be taken by some other data
126 # not sure if it is a bug or some weird sort of feature, but masking it out
127 # gets the count right (unless, of course, someone's dictionaries grow
128 # too large - but I have not tested this)
129 if self.sys_params.is_64_bit:
130 value = value & ~0xFF00000000000000
131 else:
132 value = value & ~0xFF000000
133 return value
134
Enrico Granataeb4a4792012-02-23 23:10:27 +0000135
136class NSSetM_SummaryProvider:
Enrico Granataeb4a4792012-02-23 23:10:27 +0000137
Kate Stoneb9c1b512016-09-06 20:57:50 +0000138 def adjust_for_architecture(self):
139 pass
Enrico Granataeb4a4792012-02-23 23:10:27 +0000140
Kate Stoneb9c1b512016-09-06 20:57:50 +0000141 def __init__(self, valobj, params):
142 logger = lldb.formatters.Logger.Logger()
143 self.valobj = valobj
144 self.sys_params = params
145 if not(self.sys_params.types_cache.NSUInteger):
146 if self.sys_params.is_64_bit:
147 self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
148 ).GetBasicType(lldb.eBasicTypeUnsignedLong)
149 else:
150 self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
151 ).GetBasicType(lldb.eBasicTypeUnsignedInt)
152 self.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +0000153
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154 def update(self):
155 logger = lldb.formatters.Logger.Logger()
156 self.adjust_for_architecture()
Enrico Granataeb4a4792012-02-23 23:10:27 +0000157
Kate Stoneb9c1b512016-09-06 20:57:50 +0000158 # we just need to skip the ISA and the count immediately follows
159 def offset(self):
160 logger = lldb.formatters.Logger.Logger()
161 return self.sys_params.pointer_size
162
163 def count(self):
164 logger = lldb.formatters.Logger.Logger()
165 num_children_vo = self.valobj.CreateChildAtOffset(
166 "count", self.offset(), self.sys_params.types_cache.NSUInteger)
167 return num_children_vo.GetValueAsUnsigned(0)
Enrico Granataeb4a4792012-02-23 23:10:27 +0000168
169
Enrico Granata896cd1d2012-03-01 19:32:33 +0000170class NSCountedSet_SummaryProvider:
Enrico Granata896cd1d2012-03-01 19:32:33 +0000171
Kate Stoneb9c1b512016-09-06 20:57:50 +0000172 def adjust_for_architecture(self):
173 pass
Enrico Granata896cd1d2012-03-01 19:32:33 +0000174
Kate Stoneb9c1b512016-09-06 20:57:50 +0000175 def __init__(self, valobj, params):
176 logger = lldb.formatters.Logger.Logger()
177 self.valobj = valobj
178 self.sys_params = params
179 if not (self.sys_params.types_cache.voidptr):
180 self.sys_params.types_cache.voidptr = self.valobj.GetType(
181 ).GetBasicType(lldb.eBasicTypeVoid).GetPointerType()
182 self.update()
Enrico Granata896cd1d2012-03-01 19:32:33 +0000183
Kate Stoneb9c1b512016-09-06 20:57:50 +0000184 def update(self):
185 logger = lldb.formatters.Logger.Logger()
186 self.adjust_for_architecture()
Enrico Granata896cd1d2012-03-01 19:32:33 +0000187
Kate Stoneb9c1b512016-09-06 20:57:50 +0000188 # an NSCountedSet is implemented using a CFBag whose pointer just follows
189 # the ISA
190 def offset(self):
191 logger = lldb.formatters.Logger.Logger()
192 return self.sys_params.pointer_size
193
194 def count(self):
195 logger = lldb.formatters.Logger.Logger()
196 cfbag_vo = self.valobj.CreateChildAtOffset(
197 "bag_impl", self.offset(), self.sys_params.types_cache.voidptr)
198 return CFBag.CFBagRef_SummaryProvider(
199 cfbag_vo, self.sys_params).length()
Enrico Granata896cd1d2012-03-01 19:32:33 +0000200
201
Enrico Granataeb4a4792012-02-23 23:10:27 +0000202def GetSummary_Impl(valobj):
Kate Stoneb9c1b512016-09-06 20:57:50 +0000203 logger = lldb.formatters.Logger.Logger()
204 global statistics
205 class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
206 valobj, statistics)
207 if wrapper:
208 return wrapper
Enrico Granata247bd412012-04-02 16:39:29 +0000209
Kate Stoneb9c1b512016-09-06 20:57:50 +0000210 name_string = class_data.class_name()
211 logger >> "class name is: " + str(name_string)
212
213 if name_string == '__NSCFSet':
214 wrapper = NSCFSet_SummaryProvider(valobj, class_data.sys_params)
215 statistics.metric_hit('code_notrun', valobj)
216 elif name_string == '__NSSetI':
217 wrapper = NSSetI_SummaryProvider(valobj, class_data.sys_params)
218 statistics.metric_hit('code_notrun', valobj)
219 elif name_string == '__NSSetM':
220 wrapper = NSSetM_SummaryProvider(valobj, class_data.sys_params)
221 statistics.metric_hit('code_notrun', valobj)
222 elif name_string == 'NSCountedSet':
223 wrapper = NSCountedSet_SummaryProvider(valobj, class_data.sys_params)
224 statistics.metric_hit('code_notrun', valobj)
225 else:
226 wrapper = NSSetUnknown_SummaryProvider(valobj, class_data.sys_params)
227 statistics.metric_hit(
228 'unknown_class',
229 valobj.GetName() +
230 " seen as " +
231 name_string)
232 return wrapper
Enrico Granataeb4a4792012-02-23 23:10:27 +0000233
234
Kate Stoneb9c1b512016-09-06 20:57:50 +0000235def NSSet_SummaryProvider(valobj, dict):
236 logger = lldb.formatters.Logger.Logger()
237 provider = GetSummary_Impl(valobj)
238 if provider is not None:
239 try:
240 summary = provider.count()
241 except:
242 summary = None
243 if summary is None:
244 summary = '<variable is not NSSet>'
245 if isinstance(summary, basestring):
246 return summary
247 else:
248 summary = str(summary) + \
249 (' objects' if summary != 1 else ' object')
250 return summary
251 return 'Summary Unavailable'
Enrico Granataeb4a4792012-02-23 23:10:27 +0000252
253
Kate Stoneb9c1b512016-09-06 20:57:50 +0000254def NSSet_SummaryProvider2(valobj, dict):
255 logger = lldb.formatters.Logger.Logger()
256 provider = GetSummary_Impl(valobj)
257 if provider is not None:
258 if isinstance(
259 provider,
260 lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
261 return provider.message()
262 try:
263 summary = provider.count()
264 except:
265 summary = None
266 logger >> "got summary " + str(summary)
267 # for some reason, one needs to clear some bits for the count returned
268 # to be correct when using directly CF*SetRef as compared to NS*Set
269 # this only happens on 64bit, and the bit mask was derived through
270 # experimentation (if counts start looking weird, then most probably
271 # the mask needs to be changed)
272 if summary is None:
273 summary = '<variable is not CFSet>'
274 if isinstance(summary, basestring):
275 return summary
276 else:
277 if provider.sys_params.is_64_bit:
278 summary = summary & ~0x1fff000000000000
279 summary = '@"' + str(summary) + \
280 (' values"' if summary != 1 else ' value"')
281 return summary
282 return 'Summary Unavailable'
283
284
285def __lldb_init_module(debugger, dict):
286 debugger.HandleCommand(
287 "type summary add -F NSSet.NSSet_SummaryProvider NSSet")
288 debugger.HandleCommand(
289 "type summary add -F NSSet.NSSet_SummaryProvider2 CFSetRef CFMutableSetRef")