blob: 5bd9e690b36bd5c4999cfd38897fc3e0b63e368e [file] [log] [blame]
Enrico Granataeb4a4792012-02-23 23:10:27 +00001# summary provider for NSDictionary
2import lldb
3import ctypes
4import objc_runtime
5import metrics
6
7statistics = metrics.Metrics()
8statistics.add_metric('invalid_isa')
9statistics.add_metric('invalid_pointer')
10statistics.add_metric('unknown_class')
11statistics.add_metric('code_notrun')
12
13# despite the similary to synthetic children providers, these classes are not
14# trying to provide anything but the count for an NSDictionary, so they need not
15# obey the interface specification for synthetic children providers
16class NSCFDictionary_SummaryProvider:
17 def adjust_for_architecture(self):
Enrico Granata7bc0ec32012-02-29 03:28:49 +000018 self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8)
Enrico Granataeb4a4792012-02-23 23:10:27 +000019 self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle)
20 self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize()
21
22 def __init__(self, valobj):
23 self.valobj = valobj;
24 self.update();
25
26 def update(self):
27 self.adjust_for_architecture();
28 self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID)
Enrico Granata7bc0ec32012-02-29 03:28:49 +000029 if self.is_64_bit:
Enrico Granataeb4a4792012-02-23 23:10:27 +000030 self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
31 else:
32 self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
33
34 # empirically determined on both 32 and 64bit desktop Mac OS X
35 # probably boils down to 2 pointers and 4 bytes of data, but
36 # the description of __CFDictionary is not readily available so most
37 # of this is guesswork, plain and simple
38 def offset(self):
Enrico Granata7bc0ec32012-02-29 03:28:49 +000039 if self.is_64_bit:
Enrico Granataeb4a4792012-02-23 23:10:27 +000040 return 20
41 else:
42 return 12
43
44 def num_children(self):
45 num_children_vo = self.valobj.CreateChildAtOffset("count",
46 self.offset(),
47 self.NSUInteger)
48 return num_children_vo.GetValueAsUnsigned(0)
49
50
51class NSDictionaryI_SummaryProvider:
52 def adjust_for_architecture(self):
Enrico Granata7bc0ec32012-02-29 03:28:49 +000053 self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8)
Enrico Granataeb4a4792012-02-23 23:10:27 +000054 self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle)
55 self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize()
56
57 def __init__(self, valobj):
58 self.valobj = valobj;
59 self.update();
60
61 def update(self):
62 self.adjust_for_architecture();
63 self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID)
Enrico Granata7bc0ec32012-02-29 03:28:49 +000064 if self.is_64_bit:
Enrico Granataeb4a4792012-02-23 23:10:27 +000065 self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
66 else:
67 self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
68
69 # we just need to skip the ISA and the count immediately follows
70 def offset(self):
Enrico Granata7bc0ec32012-02-29 03:28:49 +000071 if self.is_64_bit:
Enrico Granataeb4a4792012-02-23 23:10:27 +000072 return 8
73 else:
74 return 4
75
76 def num_children(self):
77 num_children_vo = self.valobj.CreateChildAtOffset("count",
78 self.offset(),
79 self.NSUInteger)
80 value = num_children_vo.GetValueAsUnsigned(0)
81 if value != None:
Enrico Granata7bc0ec32012-02-29 03:28:49 +000082 # the MS6bits on immutable dictionaries seem to be taken by the LSB of capacity
83 # not sure if it is a bug or some weird sort of feature, but masking that out
84 # gets the count right
85 if self.is_64_bit:
86 value = value & ~0xFC00000000000000
Enrico Granataeb4a4792012-02-23 23:10:27 +000087 else:
Enrico Granata7bc0ec32012-02-29 03:28:49 +000088 value = value & ~0xFC000000
Enrico Granataeb4a4792012-02-23 23:10:27 +000089 return value
90
91class NSDictionaryM_SummaryProvider:
92 def adjust_for_architecture(self):
Enrico Granata7bc0ec32012-02-29 03:28:49 +000093 self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8)
Enrico Granataeb4a4792012-02-23 23:10:27 +000094 self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle)
95 self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize()
96
97 def __init__(self, valobj):
98 self.valobj = valobj;
99 self.update();
100
101 def update(self):
102 self.adjust_for_architecture();
103 self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID)
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000104 if self.is_64_bit:
Enrico Granataeb4a4792012-02-23 23:10:27 +0000105 self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
106 else:
107 self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
108
109 # we just need to skip the ISA and the count immediately follows
110 def offset(self):
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000111 if self.is_64_bit:
Enrico Granataeb4a4792012-02-23 23:10:27 +0000112 return 8
113 else:
114 return 4
115
116 def num_children(self):
117 num_children_vo = self.valobj.CreateChildAtOffset("count",
118 self.offset(),
119 self.NSUInteger)
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000120 value = num_children_vo.GetValueAsUnsigned(0)
121 if value != None:
122 # the MS6bits on mutable dictionaries seem to be taken by flags for
123 # KVO and probably other features. however, masking it out does get
124 # the count right
125 if self.is_64_bit:
126 value = value & ~0xFC00000000000000
127 else:
128 value = value & ~0xFC000000
129 return value
Enrico Granataeb4a4792012-02-23 23:10:27 +0000130
131
132class NSDictionaryUnknown_SummaryProvider:
133 def adjust_for_architecture(self):
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000134 self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8)
Enrico Granataeb4a4792012-02-23 23:10:27 +0000135 self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle)
136 self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize()
137
138 def __init__(self, valobj):
139 self.valobj = valobj;
140 self.update()
141
142 def update(self):
143 self.adjust_for_architecture();
144 self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID)
145
146 def num_children(self):
147 stream = lldb.SBStream()
148 self.valobj.GetExpressionPath(stream)
149 num_children_vo = self.valobj.CreateValueFromExpression("count","(int)[" + stream.GetData() + " count]");
150 return num_children_vo.GetValueAsUnsigned(0)
151
152
153def GetSummary_Impl(valobj):
154 global statistics
155 class_data = objc_runtime.ObjCRuntime(valobj)
156 if class_data.is_valid() == False:
157 statistics.metric_hit('invalid_pointer',valobj)
158 wrapper = None
159 return
160 class_data = class_data.read_class_data()
161 if class_data.is_valid() == False:
162 statistics.metric_hit('invalid_isa',valobj)
163 wrapper = None
164 return
165 if class_data.is_kvo():
166 class_data = class_data.get_superclass()
167 if class_data.is_valid() == False:
168 statistics.metric_hit('invalid_isa',valobj)
169 wrapper = None
170 return
171
172 name_string = class_data.class_name()
173 if name_string == '__NSCFDictionary':
174 wrapper = NSCFDictionary_SummaryProvider(valobj)
175 statistics.metric_hit('code_notrun',valobj)
176 elif name_string == '__NSDictionaryI':
177 wrapper = NSDictionaryI_SummaryProvider(valobj)
178 statistics.metric_hit('code_notrun',valobj)
179 elif name_string == '__NSDictionaryM':
180 wrapper = NSDictionaryM_SummaryProvider(valobj)
181 statistics.metric_hit('code_notrun',valobj)
182 else:
183 wrapper = NSDictionaryUnknown_SummaryProvider(valobj)
184 statistics.metric_hit('unknown_class',str(valobj) + " seen as " + name_string)
185 return wrapper;
186
187def CFDictionary_SummaryProvider (valobj,dict):
188 provider = GetSummary_Impl(valobj);
189 if provider != None:
190 try:
191 summary = str(provider.num_children());
192 except:
193 summary = None
194 if summary == None:
195 summary = 'no valid dictionary here'
196 return summary + " key/value pairs"
197 return ''
198
199def CFDictionary_SummaryProvider2 (valobj,dict):
200 provider = GetSummary_Impl(valobj);
201 if provider != None:
202 try:
203 summary = (provider.num_children());
204 except:
205 summary = None
206 if summary == None:
207 summary = 'no valid dictionary here'
208 # needed on OSX Mountain Lion
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000209 elif provider.is_64_bit:
Enrico Granataeb4a4792012-02-23 23:10:27 +0000210 summary = int(summary) & ~0x0f1f000000000000
211 return str(summary) + " key/value pairs"
212 return ''
213
214def __lldb_init_module(debugger,dict):
215 debugger.HandleCommand("type summary add -F CFDictionary.CFDictionary_SummaryProvider NSDictionary")
216 debugger.HandleCommand("type summary add -F CFDictionary.CFDictionary_SummaryProvider2 CFDictionaryRef CFMutableDictionaryRef")