Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lldb / examples / summaries / cocoa / NSSet.py
blobcd554bfc3cb580dfa83131721486aac5d48dc5f1
1 """
2 LLDB AppKit formatters
4 Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 See https://llvm.org/LICENSE.txt for license information.
6 SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 """
8 # summary provider for NSSet
9 import lldb
10 import ctypes
11 import lldb.runtime.objc.objc_runtime
12 import lldb.formatters.metrics
13 import CFBag
14 import lldb.formatters.Logger
16 statistics = lldb.formatters.metrics.Metrics()
17 statistics.add_metric("invalid_isa")
18 statistics.add_metric("invalid_pointer")
19 statistics.add_metric("unknown_class")
20 statistics.add_metric("code_notrun")
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
27 class NSCFSet_SummaryProvider:
28 def adjust_for_architecture(self):
29 pass
31 def __init__(self, valobj, params):
32 logger = lldb.formatters.Logger.Logger()
33 self.valobj = valobj
34 self.sys_params = params
35 if not (self.sys_params.types_cache.NSUInteger):
36 if self.sys_params.is_64_bit:
37 self.sys_params.types_cache.NSUInteger = (
38 self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
40 else:
41 self.sys_params.types_cache.NSUInteger = (
42 self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
44 self.update()
46 def update(self):
47 logger = lldb.formatters.Logger.Logger()
48 self.adjust_for_architecture()
50 # one pointer is the ISA
51 # then we have one other internal pointer, plus
52 # 4 bytes worth of flags. hence, these values
53 def offset(self):
54 logger = lldb.formatters.Logger.Logger()
55 if self.sys_params.is_64_bit:
56 return 20
57 else:
58 return 12
60 def count(self):
61 logger = lldb.formatters.Logger.Logger()
62 vcount = self.valobj.CreateChildAtOffset(
63 "count", self.offset(), self.sys_params.types_cache.NSUInteger
65 return vcount.GetValueAsUnsigned(0)
68 class NSSetUnknown_SummaryProvider:
69 def adjust_for_architecture(self):
70 pass
72 def __init__(self, valobj, params):
73 logger = lldb.formatters.Logger.Logger()
74 self.valobj = valobj
75 self.sys_params = params
76 self.update()
78 def update(self):
79 logger = lldb.formatters.Logger.Logger()
80 self.adjust_for_architecture()
82 def count(self):
83 logger = lldb.formatters.Logger.Logger()
84 stream = lldb.SBStream()
85 self.valobj.GetExpressionPath(stream)
86 expr = "(int)[" + stream.GetData() + " count]"
87 num_children_vo = self.valobj.CreateValueFromExpression("count", expr)
88 if num_children_vo.IsValid():
89 return num_children_vo.GetValueAsUnsigned(0)
90 return "<variable is not NSSet>"
93 class NSSetI_SummaryProvider:
94 def adjust_for_architecture(self):
95 pass
97 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 = (
104 self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
106 else:
107 self.sys_params.types_cache.NSUInteger = (
108 self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
110 self.update()
112 def update(self):
113 logger = lldb.formatters.Logger.Logger()
114 self.adjust_for_architecture()
116 # we just need to skip the ISA and the count immediately follows
117 def offset(self):
118 logger = lldb.formatters.Logger.Logger()
119 return self.sys_params.pointer_size
121 def count(self):
122 logger = lldb.formatters.Logger.Logger()
123 num_children_vo = self.valobj.CreateChildAtOffset(
124 "count", self.offset(), self.sys_params.types_cache.NSUInteger
126 value = num_children_vo.GetValueAsUnsigned(0)
127 if value is not None:
128 # the MSB on immutable sets seems to be taken by some other data
129 # not sure if it is a bug or some weird sort of feature, but masking it out
130 # gets the count right (unless, of course, someone's dictionaries grow
131 # too large - but I have not tested this)
132 if self.sys_params.is_64_bit:
133 value = value & ~0xFF00000000000000
134 else:
135 value = value & ~0xFF000000
136 return value
139 class NSSetM_SummaryProvider:
140 def adjust_for_architecture(self):
141 pass
143 def __init__(self, valobj, params):
144 logger = lldb.formatters.Logger.Logger()
145 self.valobj = valobj
146 self.sys_params = params
147 if not (self.sys_params.types_cache.NSUInteger):
148 if self.sys_params.is_64_bit:
149 self.sys_params.types_cache.NSUInteger = (
150 self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
152 else:
153 self.sys_params.types_cache.NSUInteger = (
154 self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
156 self.update()
158 def update(self):
159 logger = lldb.formatters.Logger.Logger()
160 self.adjust_for_architecture()
162 # we just need to skip the ISA and the count immediately follows
163 def offset(self):
164 logger = lldb.formatters.Logger.Logger()
165 return self.sys_params.pointer_size
167 def count(self):
168 logger = lldb.formatters.Logger.Logger()
169 num_children_vo = self.valobj.CreateChildAtOffset(
170 "count", self.offset(), self.sys_params.types_cache.NSUInteger
172 return num_children_vo.GetValueAsUnsigned(0)
175 class NSCountedSet_SummaryProvider:
176 def adjust_for_architecture(self):
177 pass
179 def __init__(self, valobj, params):
180 logger = lldb.formatters.Logger.Logger()
181 self.valobj = valobj
182 self.sys_params = params
183 if not (self.sys_params.types_cache.voidptr):
184 self.sys_params.types_cache.voidptr = (
185 self.valobj.GetType().GetBasicType(lldb.eBasicTypeVoid).GetPointerType()
187 self.update()
189 def update(self):
190 logger = lldb.formatters.Logger.Logger()
191 self.adjust_for_architecture()
193 # an NSCountedSet is implemented using a CFBag whose pointer just follows
194 # the ISA
195 def offset(self):
196 logger = lldb.formatters.Logger.Logger()
197 return self.sys_params.pointer_size
199 def count(self):
200 logger = lldb.formatters.Logger.Logger()
201 cfbag_vo = self.valobj.CreateChildAtOffset(
202 "bag_impl", self.offset(), self.sys_params.types_cache.voidptr
204 return CFBag.CFBagRef_SummaryProvider(cfbag_vo, self.sys_params).length()
207 def GetSummary_Impl(valobj):
208 logger = lldb.formatters.Logger.Logger()
209 global statistics
211 class_data,
212 wrapper,
213 ) = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
214 valobj, statistics
216 if wrapper:
217 return wrapper
219 name_string = class_data.class_name()
220 logger >> "class name is: " + str(name_string)
222 if name_string == "__NSCFSet":
223 wrapper = NSCFSet_SummaryProvider(valobj, class_data.sys_params)
224 statistics.metric_hit("code_notrun", valobj)
225 elif name_string == "__NSSetI":
226 wrapper = NSSetI_SummaryProvider(valobj, class_data.sys_params)
227 statistics.metric_hit("code_notrun", valobj)
228 elif name_string == "__NSSetM":
229 wrapper = NSSetM_SummaryProvider(valobj, class_data.sys_params)
230 statistics.metric_hit("code_notrun", valobj)
231 elif name_string == "NSCountedSet":
232 wrapper = NSCountedSet_SummaryProvider(valobj, class_data.sys_params)
233 statistics.metric_hit("code_notrun", valobj)
234 else:
235 wrapper = NSSetUnknown_SummaryProvider(valobj, class_data.sys_params)
236 statistics.metric_hit(
237 "unknown_class", valobj.GetName() + " seen as " + name_string
239 return wrapper
242 def NSSet_SummaryProvider(valobj, dict):
243 logger = lldb.formatters.Logger.Logger()
244 provider = GetSummary_Impl(valobj)
245 if provider is not None:
246 try:
247 summary = provider.count()
248 except:
249 summary = None
250 if summary is None:
251 summary = "<variable is not NSSet>"
252 if isinstance(summary, str):
253 return summary
254 else:
255 summary = str(summary) + (" objects" if summary != 1 else " object")
256 return summary
257 return "Summary Unavailable"
260 def NSSet_SummaryProvider2(valobj, dict):
261 logger = lldb.formatters.Logger.Logger()
262 provider = GetSummary_Impl(valobj)
263 if provider is not None:
264 if isinstance(
265 provider, lldb.runtime.objc.objc_runtime.SpecialSituation_Description
267 return provider.message()
268 try:
269 summary = provider.count()
270 except:
271 summary = None
272 logger >> "got summary " + str(summary)
273 # for some reason, one needs to clear some bits for the count returned
274 # to be correct when using directly CF*SetRef as compared to NS*Set
275 # this only happens on 64bit, and the bit mask was derived through
276 # experimentation (if counts start looking weird, then most probably
277 # the mask needs to be changed)
278 if summary is None:
279 summary = "<variable is not CFSet>"
280 if isinstance(summary, str):
281 return summary
282 else:
283 if provider.sys_params.is_64_bit:
284 summary = summary & ~0x1FFF000000000000
285 summary = '@"' + str(summary) + (' values"' if summary != 1 else ' value"')
286 return summary
287 return "Summary Unavailable"
290 def __lldb_init_module(debugger, dict):
291 debugger.HandleCommand("type summary add -F NSSet.NSSet_SummaryProvider NSSet")
292 debugger.HandleCommand(
293 "type summary add -F NSSet.NSSet_SummaryProvider2 CFSetRef CFMutableSetRef"