4 part of The LLVM Compiler Infrastructure
5 This file is distributed under the University of Illinois Open Source
6 License. See LICENSE.TXT for details.
8 # example summary provider for NSDictionary
9 # the real summary is now C++ code built into LLDB
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
25 class NSCFDictionary_SummaryProvider:
26 def adjust_for_architecture(self):
29 def __init__(self, valobj, params):
30 logger = lldb.formatters.Logger.Logger()
32 self.sys_params = params
33 if not(self.sys_params.types_cache.NSUInteger):
34 if self.sys_params.is_64_bit:
35 self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
37 self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
41 logger = lldb.formatters.Logger.Logger()
42 self.adjust_for_architecture();
44 # empirically determined on both 32 and 64bit desktop Mac OS X
45 # probably boils down to 2 pointers and 4 bytes of data, but
46 # the description of __CFDictionary is not readily available so most
47 # of this is guesswork, plain and simple
49 logger = lldb.formatters.Logger.Logger()
50 if self.sys_params.is_64_bit:
55 def num_children(self):
56 logger = lldb.formatters.Logger.Logger()
57 num_children_vo = self.valobj.CreateChildAtOffset("count",
59 self.sys_params.types_cache.NSUInteger)
60 return num_children_vo.GetValueAsUnsigned(0)
63 class NSDictionaryI_SummaryProvider:
64 def adjust_for_architecture(self):
67 def __init__(self, valobj, params):
68 logger = lldb.formatters.Logger.Logger()
70 self.sys_params = params
71 if not(self.sys_params.types_cache.NSUInteger):
72 if self.sys_params.is_64_bit:
73 self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
75 self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
79 logger = lldb.formatters.Logger.Logger()
80 self.adjust_for_architecture();
82 # we just need to skip the ISA and the count immediately follows
84 logger = lldb.formatters.Logger.Logger()
85 return self.sys_params.pointer_size
87 def num_children(self):
88 logger = lldb.formatters.Logger.Logger()
89 num_children_vo = self.valobj.CreateChildAtOffset("count",
91 self.sys_params.types_cache.NSUInteger)
92 value = num_children_vo.GetValueAsUnsigned(0)
94 # the MS6bits on immutable dictionaries seem to be taken by the LSB of capacity
95 # not sure if it is a bug or some weird sort of feature, but masking that out
96 # gets the count right
97 if self.sys_params.is_64_bit:
98 value = value & ~0xFC00000000000000
100 value = value & ~0xFC000000
103 class NSDictionaryM_SummaryProvider:
104 def adjust_for_architecture(self):
107 def __init__(self, valobj, params):
108 logger = lldb.formatters.Logger.Logger()
109 self.valobj = valobj;
110 self.sys_params = params
111 if not(self.sys_params.types_cache.NSUInteger):
112 if self.sys_params.is_64_bit:
113 self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
115 self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
119 logger = lldb.formatters.Logger.Logger()
120 self.adjust_for_architecture();
122 # we just need to skip the ISA and the count immediately follows
124 return self.sys_params.pointer_size
126 def num_children(self):
127 logger = lldb.formatters.Logger.Logger()
128 num_children_vo = self.valobj.CreateChildAtOffset("count",
130 self.sys_params.types_cache.NSUInteger)
131 value = num_children_vo.GetValueAsUnsigned(0)
133 # the MS6bits on immutable dictionaries seem to be taken by the LSB of capacity
134 # not sure if it is a bug or some weird sort of feature, but masking that out
135 # gets the count right
136 if self.sys_params.is_64_bit:
137 value = value & ~0xFC00000000000000
139 value = value & ~0xFC000000
142 class NSDictionaryUnknown_SummaryProvider:
143 def adjust_for_architecture(self):
146 def __init__(self, valobj, params):
147 logger = lldb.formatters.Logger.Logger()
148 self.valobj = valobj;
149 self.sys_params = params
153 logger = lldb.formatters.Logger.Logger()
154 self.adjust_for_architecture();
156 def num_children(self):
157 logger = lldb.formatters.Logger.Logger()
158 stream = lldb.SBStream()
159 self.valobj.GetExpressionPath(stream)
160 num_children_vo = self.valobj.CreateValueFromExpression("count","(int)[" + stream.GetData() + " count]");
161 if num_children_vo.IsValid():
162 return num_children_vo.GetValueAsUnsigned(0)
163 return '<variable is not NSDictionary>'
166 def GetSummary_Impl(valobj):
167 logger = lldb.formatters.Logger.Logger()
169 class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics)
173 name_string = class_data.class_name()
175 logger >> "class name is: " + str(name_string)
177 if name_string == '__NSCFDictionary':
178 wrapper = NSCFDictionary_SummaryProvider(valobj, class_data.sys_params)
179 statistics.metric_hit('code_notrun',valobj)
180 elif name_string == '__NSDictionaryI':
181 wrapper = NSDictionaryI_SummaryProvider(valobj, class_data.sys_params)
182 statistics.metric_hit('code_notrun',valobj)
183 elif name_string == '__NSDictionaryM':
184 wrapper = NSDictionaryM_SummaryProvider(valobj, class_data.sys_params)
185 statistics.metric_hit('code_notrun',valobj)
187 wrapper = NSDictionaryUnknown_SummaryProvider(valobj, class_data.sys_params)
188 statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
191 def CFDictionary_SummaryProvider (valobj,dict):
192 logger = lldb.formatters.Logger.Logger()
193 provider = GetSummary_Impl(valobj);
195 if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
196 return provider.message()
198 summary = provider.num_children();
201 logger >> "got summary " + str(summary)
203 return '<variable is not NSDictionary>'
204 if isinstance(summary,basestring):
206 return str(summary) + (" key/value pairs" if summary != 1 else " key/value pair")
207 return 'Summary Unavailable'
209 def CFDictionary_SummaryProvider2 (valobj,dict):
210 logger = lldb.formatters.Logger.Logger()
211 provider = GetSummary_Impl(valobj);
213 if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
214 return provider.message()
216 summary = provider.num_children();
219 logger >> "got summary " + str(summary)
221 summary = '<variable is not CFDictionary>'
222 if isinstance(summary,basestring):
225 # needed on OSX Mountain Lion
226 if provider.sys_params.is_64_bit:
227 summary = summary & ~0x0f1f000000000000
228 summary = '@"' + str(summary) + (' entries"' if summary != 1 else ' entry"')
230 return 'Summary Unavailable'
232 def __lldb_init_module(debugger,dict):
233 debugger.HandleCommand("type summary add -F CFDictionary.CFDictionary_SummaryProvider NSDictionary")
234 debugger.HandleCommand("type summary add -F CFDictionary.CFDictionary_SummaryProvider2 CFDictionaryRef CFMutableDictionaryRef")