blob: 92d8048470c09d978521f03bf03aa3147d69d9c6 [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 Granata3467d802012-09-04 18:47:54 +00008# example summary provider for NSDictionary
9# the real summary is now C++ code built into LLDB
Enrico Granataeb4a4792012-02-23 23:10:27 +000010import lldb
11import ctypes
Enrico Granata28399ad2012-04-25 01:39:27 +000012import lldb.runtime.objc.objc_runtime
13import lldb.formatters.metrics
14import 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 count for an NSDictionary, 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 NSCFDictionary_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 # empirically determined on both 32 and 64bit desktop Mac OS X
50 # probably boils down to 2 pointers and 4 bytes of data, but
51 # the description of __CFDictionary is not readily available so most
52 # of this is guesswork, plain and simple
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
59
60 def num_children(self):
61 logger = lldb.formatters.Logger.Logger()
62 num_children_vo = self.valobj.CreateChildAtOffset(
63 "count", self.offset(), self.sys_params.types_cache.NSUInteger)
64 return num_children_vo.GetValueAsUnsigned(0)
Enrico Granataeb4a4792012-02-23 23:10:27 +000065
66
67class NSDictionaryI_SummaryProvider:
Enrico Granataeb4a4792012-02-23 23:10:27 +000068
Kate Stoneb9c1b512016-09-06 20:57:50 +000069 def adjust_for_architecture(self):
70 pass
Enrico Granataeb4a4792012-02-23 23:10:27 +000071
Kate Stoneb9c1b512016-09-06 20:57:50 +000072 def __init__(self, valobj, params):
73 logger = lldb.formatters.Logger.Logger()
74 self.valobj = valobj
75 self.sys_params = params
76 if not(self.sys_params.types_cache.NSUInteger):
77 if self.sys_params.is_64_bit:
78 self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
79 ).GetBasicType(lldb.eBasicTypeUnsignedLong)
80 else:
81 self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
82 ).GetBasicType(lldb.eBasicTypeUnsignedInt)
83 self.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +000084
Kate Stoneb9c1b512016-09-06 20:57:50 +000085 def update(self):
86 logger = lldb.formatters.Logger.Logger()
87 self.adjust_for_architecture()
Enrico Granataeb4a4792012-02-23 23:10:27 +000088
Kate Stoneb9c1b512016-09-06 20:57:50 +000089 # we just need to skip the ISA and the count immediately follows
90 def offset(self):
91 logger = lldb.formatters.Logger.Logger()
92 return self.sys_params.pointer_size
93
94 def num_children(self):
95 logger = lldb.formatters.Logger.Logger()
96 num_children_vo = self.valobj.CreateChildAtOffset(
97 "count", self.offset(), self.sys_params.types_cache.NSUInteger)
98 value = num_children_vo.GetValueAsUnsigned(0)
99 if value is not None:
100 # the MS6bits on immutable dictionaries seem to be taken by the LSB of capacity
101 # not sure if it is a bug or some weird sort of feature, but masking that out
102 # gets the count right
103 if self.sys_params.is_64_bit:
104 value = value & ~0xFC00000000000000
105 else:
106 value = value & ~0xFC000000
107 return value
108
Enrico Granataeb4a4792012-02-23 23:10:27 +0000109
110class NSDictionaryM_SummaryProvider:
Enrico Granataeb4a4792012-02-23 23:10:27 +0000111
Kate Stoneb9c1b512016-09-06 20:57:50 +0000112 def adjust_for_architecture(self):
113 pass
Enrico Granataeb4a4792012-02-23 23:10:27 +0000114
Kate Stoneb9c1b512016-09-06 20:57:50 +0000115 def __init__(self, valobj, params):
116 logger = lldb.formatters.Logger.Logger()
117 self.valobj = valobj
118 self.sys_params = params
119 if not(self.sys_params.types_cache.NSUInteger):
120 if self.sys_params.is_64_bit:
121 self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
122 ).GetBasicType(lldb.eBasicTypeUnsignedLong)
123 else:
124 self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
125 ).GetBasicType(lldb.eBasicTypeUnsignedInt)
126 self.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +0000127
Kate Stoneb9c1b512016-09-06 20:57:50 +0000128 def update(self):
129 logger = lldb.formatters.Logger.Logger()
130 self.adjust_for_architecture()
Enrico Granataeb4a4792012-02-23 23:10:27 +0000131
Kate Stoneb9c1b512016-09-06 20:57:50 +0000132 # we just need to skip the ISA and the count immediately follows
133 def offset(self):
134 return self.sys_params.pointer_size
135
136 def num_children(self):
137 logger = lldb.formatters.Logger.Logger()
138 num_children_vo = self.valobj.CreateChildAtOffset(
139 "count", self.offset(), self.sys_params.types_cache.NSUInteger)
140 value = num_children_vo.GetValueAsUnsigned(0)
141 if value is not None:
142 # the MS6bits on immutable dictionaries seem to be taken by the LSB of capacity
143 # not sure if it is a bug or some weird sort of feature, but masking that out
144 # gets the count right
145 if self.sys_params.is_64_bit:
146 value = value & ~0xFC00000000000000
147 else:
148 value = value & ~0xFC000000
149 return value
150
Enrico Granataeb4a4792012-02-23 23:10:27 +0000151
Enrico Granataeb4a4792012-02-23 23:10:27 +0000152class NSDictionaryUnknown_SummaryProvider:
Enrico Granataeb4a4792012-02-23 23:10:27 +0000153
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154 def adjust_for_architecture(self):
155 pass
Enrico Granataeb4a4792012-02-23 23:10:27 +0000156
Kate Stoneb9c1b512016-09-06 20:57:50 +0000157 def __init__(self, valobj, params):
158 logger = lldb.formatters.Logger.Logger()
159 self.valobj = valobj
160 self.sys_params = params
161 self.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +0000162
Kate Stoneb9c1b512016-09-06 20:57:50 +0000163 def update(self):
164 logger = lldb.formatters.Logger.Logger()
165 self.adjust_for_architecture()
166
167 def num_children(self):
168 logger = lldb.formatters.Logger.Logger()
169 stream = lldb.SBStream()
170 self.valobj.GetExpressionPath(stream)
171 num_children_vo = self.valobj.CreateValueFromExpression(
172 "count", "(int)[" + stream.GetData() + " count]")
173 if num_children_vo.IsValid():
174 return num_children_vo.GetValueAsUnsigned(0)
175 return '<variable is not NSDictionary>'
Enrico Granataeb4a4792012-02-23 23:10:27 +0000176
177
178def GetSummary_Impl(valobj):
Kate Stoneb9c1b512016-09-06 20:57:50 +0000179 logger = lldb.formatters.Logger.Logger()
180 global statistics
181 class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
182 valobj, statistics)
183 if wrapper:
184 return wrapper
Enrico Granataeb4a4792012-02-23 23:10:27 +0000185
Kate Stoneb9c1b512016-09-06 20:57:50 +0000186 name_string = class_data.class_name()
Enrico Granata3f1052b2012-03-13 21:52:00 +0000187
Kate Stoneb9c1b512016-09-06 20:57:50 +0000188 logger >> "class name is: " + str(name_string)
Enrico Granataeb4a4792012-02-23 23:10:27 +0000189
Kate Stoneb9c1b512016-09-06 20:57:50 +0000190 if name_string == '__NSCFDictionary':
191 wrapper = NSCFDictionary_SummaryProvider(valobj, class_data.sys_params)
192 statistics.metric_hit('code_notrun', valobj)
193 elif name_string == '__NSDictionaryI':
194 wrapper = NSDictionaryI_SummaryProvider(valobj, class_data.sys_params)
195 statistics.metric_hit('code_notrun', valobj)
196 elif name_string == '__NSDictionaryM':
197 wrapper = NSDictionaryM_SummaryProvider(valobj, class_data.sys_params)
198 statistics.metric_hit('code_notrun', valobj)
199 else:
200 wrapper = NSDictionaryUnknown_SummaryProvider(
201 valobj, class_data.sys_params)
202 statistics.metric_hit(
203 'unknown_class',
204 valobj.GetName() +
205 " seen as " +
206 name_string)
207 return wrapper
208
209
210def CFDictionary_SummaryProvider(valobj, dict):
211 logger = lldb.formatters.Logger.Logger()
212 provider = GetSummary_Impl(valobj)
213 if provider is not None:
214 if isinstance(
215 provider,
216 lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
217 return provider.message()
218 try:
219 summary = provider.num_children()
220 except:
221 summary = None
222 logger >> "got summary " + str(summary)
223 if summary is None:
224 return '<variable is not NSDictionary>'
225 if isinstance(summary, basestring):
226 return summary
227 return str(summary) + (" key/value pairs" if summary !=
228 1 else " key/value pair")
229 return 'Summary Unavailable'
230
231
232def CFDictionary_SummaryProvider2(valobj, dict):
233 logger = lldb.formatters.Logger.Logger()
234 provider = GetSummary_Impl(valobj)
235 if provider is not None:
236 if isinstance(
237 provider,
238 lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
239 return provider.message()
240 try:
241 summary = provider.num_children()
242 except:
243 summary = None
244 logger >> "got summary " + str(summary)
245 if summary is None:
246 summary = '<variable is not CFDictionary>'
247 if isinstance(summary, basestring):
248 return summary
249 else:
250 # needed on OSX Mountain Lion
251 if provider.sys_params.is_64_bit:
252 summary = summary & ~0x0f1f000000000000
253 summary = '@"' + str(summary) + \
254 (' entries"' if summary != 1 else ' entry"')
255 return summary
256 return 'Summary Unavailable'
257
258
259def __lldb_init_module(debugger, dict):
260 debugger.HandleCommand(
261 "type summary add -F CFDictionary.CFDictionary_SummaryProvider NSDictionary")
262 debugger.HandleCommand(
263 "type summary add -F CFDictionary.CFDictionary_SummaryProvider2 CFDictionaryRef CFMutableDictionaryRef")