Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lldb / examples / summaries / cocoa / CFDictionary.py
blob6b8bf390a50526999e59b76b034b11b5ea1d2407
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 # example summary provider for NSDictionary
9 # the real summary is now C++ code built into LLDB
10 import lldb
11 import ctypes
12 import lldb.runtime.objc.objc_runtime
13 import lldb.formatters.metrics
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 count for an NSDictionary, so they need not
24 # obey the interface specification for synthetic children providers
27 class NSCFDictionary_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 # empirically determined on both 32 and 64bit desktop Mac OS X
51 # probably boils down to 2 pointers and 4 bytes of data, but
52 # the description of __CFDictionary is not readily available so most
53 # of this is guesswork, plain and simple
54 def offset(self):
55 logger = lldb.formatters.Logger.Logger()
56 if self.sys_params.is_64_bit:
57 return 20
58 else:
59 return 12
61 def num_children(self):
62 logger = lldb.formatters.Logger.Logger()
63 num_children_vo = self.valobj.CreateChildAtOffset(
64 "count", self.offset(), self.sys_params.types_cache.NSUInteger
66 return num_children_vo.GetValueAsUnsigned(0)
69 class NSDictionaryI_SummaryProvider:
70 def adjust_for_architecture(self):
71 pass
73 def __init__(self, valobj, params):
74 logger = lldb.formatters.Logger.Logger()
75 self.valobj = valobj
76 self.sys_params = params
77 if not (self.sys_params.types_cache.NSUInteger):
78 if self.sys_params.is_64_bit:
79 self.sys_params.types_cache.NSUInteger = (
80 self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
82 else:
83 self.sys_params.types_cache.NSUInteger = (
84 self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
86 self.update()
88 def update(self):
89 logger = lldb.formatters.Logger.Logger()
90 self.adjust_for_architecture()
92 # we just need to skip the ISA and the count immediately follows
93 def offset(self):
94 logger = lldb.formatters.Logger.Logger()
95 return self.sys_params.pointer_size
97 def num_children(self):
98 logger = lldb.formatters.Logger.Logger()
99 num_children_vo = self.valobj.CreateChildAtOffset(
100 "count", self.offset(), self.sys_params.types_cache.NSUInteger
102 value = num_children_vo.GetValueAsUnsigned(0)
103 if value is not None:
104 # the MS6bits on immutable dictionaries seem to be taken by the LSB of capacity
105 # not sure if it is a bug or some weird sort of feature, but masking that out
106 # gets the count right
107 if self.sys_params.is_64_bit:
108 value = value & ~0xFC00000000000000
109 else:
110 value = value & ~0xFC000000
111 return value
114 class NSDictionaryM_SummaryProvider:
115 def adjust_for_architecture(self):
116 pass
118 def __init__(self, valobj, params):
119 logger = lldb.formatters.Logger.Logger()
120 self.valobj = valobj
121 self.sys_params = params
122 if not (self.sys_params.types_cache.NSUInteger):
123 if self.sys_params.is_64_bit:
124 self.sys_params.types_cache.NSUInteger = (
125 self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
127 else:
128 self.sys_params.types_cache.NSUInteger = (
129 self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
131 self.update()
133 def update(self):
134 logger = lldb.formatters.Logger.Logger()
135 self.adjust_for_architecture()
137 # we just need to skip the ISA and the count immediately follows
138 def offset(self):
139 return self.sys_params.pointer_size
141 def num_children(self):
142 logger = lldb.formatters.Logger.Logger()
143 num_children_vo = self.valobj.CreateChildAtOffset(
144 "count", self.offset(), self.sys_params.types_cache.NSUInteger
146 value = num_children_vo.GetValueAsUnsigned(0)
147 if value is not None:
148 # the MS6bits on immutable dictionaries seem to be taken by the LSB of capacity
149 # not sure if it is a bug or some weird sort of feature, but masking that out
150 # gets the count right
151 if self.sys_params.is_64_bit:
152 value = value & ~0xFC00000000000000
153 else:
154 value = value & ~0xFC000000
155 return value
158 class NSDictionaryUnknown_SummaryProvider:
159 def adjust_for_architecture(self):
160 pass
162 def __init__(self, valobj, params):
163 logger = lldb.formatters.Logger.Logger()
164 self.valobj = valobj
165 self.sys_params = params
166 self.update()
168 def update(self):
169 logger = lldb.formatters.Logger.Logger()
170 self.adjust_for_architecture()
172 def num_children(self):
173 logger = lldb.formatters.Logger.Logger()
174 stream = lldb.SBStream()
175 self.valobj.GetExpressionPath(stream)
176 num_children_vo = self.valobj.CreateValueFromExpression(
177 "count", "(int)[" + stream.GetData() + " count]"
179 if num_children_vo.IsValid():
180 return num_children_vo.GetValueAsUnsigned(0)
181 return "<variable is not NSDictionary>"
184 def GetSummary_Impl(valobj):
185 logger = lldb.formatters.Logger.Logger()
186 global statistics
188 class_data,
189 wrapper,
190 ) = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
191 valobj, statistics
193 if wrapper:
194 return wrapper
196 name_string = class_data.class_name()
198 logger >> "class name is: " + str(name_string)
200 if name_string == "__NSCFDictionary":
201 wrapper = NSCFDictionary_SummaryProvider(valobj, class_data.sys_params)
202 statistics.metric_hit("code_notrun", valobj)
203 elif name_string == "__NSDictionaryI":
204 wrapper = NSDictionaryI_SummaryProvider(valobj, class_data.sys_params)
205 statistics.metric_hit("code_notrun", valobj)
206 elif name_string == "__NSDictionaryM":
207 wrapper = NSDictionaryM_SummaryProvider(valobj, class_data.sys_params)
208 statistics.metric_hit("code_notrun", valobj)
209 else:
210 wrapper = NSDictionaryUnknown_SummaryProvider(valobj, class_data.sys_params)
211 statistics.metric_hit(
212 "unknown_class", valobj.GetName() + " seen as " + name_string
214 return wrapper
217 def CFDictionary_SummaryProvider(valobj, dict):
218 logger = lldb.formatters.Logger.Logger()
219 provider = GetSummary_Impl(valobj)
220 if provider is not None:
221 if isinstance(
222 provider, lldb.runtime.objc.objc_runtime.SpecialSituation_Description
224 return provider.message()
225 try:
226 summary = provider.num_children()
227 except:
228 summary = None
229 logger >> "got summary " + str(summary)
230 if summary is None:
231 return "<variable is not NSDictionary>"
232 if isinstance(summary, str):
233 return summary
234 return str(summary) + (
235 " key/value pairs" if summary != 1 else " key/value pair"
237 return "Summary Unavailable"
240 def CFDictionary_SummaryProvider2(valobj, dict):
241 logger = lldb.formatters.Logger.Logger()
242 provider = GetSummary_Impl(valobj)
243 if provider is not None:
244 if isinstance(
245 provider, lldb.runtime.objc.objc_runtime.SpecialSituation_Description
247 return provider.message()
248 try:
249 summary = provider.num_children()
250 except:
251 summary = None
252 logger >> "got summary " + str(summary)
253 if summary is None:
254 summary = "<variable is not CFDictionary>"
255 if isinstance(summary, str):
256 return summary
257 else:
258 # needed on OSX Mountain Lion
259 if provider.sys_params.is_64_bit:
260 summary = summary & ~0x0F1F000000000000
261 summary = '@"' + str(summary) + (' entries"' if summary != 1 else ' entry"')
262 return summary
263 return "Summary Unavailable"
266 def __lldb_init_module(debugger, dict):
267 debugger.HandleCommand(
268 "type summary add -F CFDictionary.CFDictionary_SummaryProvider NSDictionary"
270 debugger.HandleCommand(
271 "type summary add -F CFDictionary.CFDictionary_SummaryProvider2 CFDictionaryRef CFMutableDictionaryRef"