blob: 6fc97081bad52ec866c6c4f0d7bb6c11fa1c9712 [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 NSArray
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# much less functional than the other two cases below
23# just runs code to get to the count and then returns
24# no children
Kate Stoneb9c1b512016-09-06 20:57:50 +000025
26
Enrico Granataeb4a4792012-02-23 23:10:27 +000027class NSArrayKVC_SynthProvider:
28
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, dict, params):
33 logger = lldb.formatters.Logger.Logger()
34 self.valobj = valobj
35 self.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +000036
Kate Stoneb9c1b512016-09-06 20:57:50 +000037 def update(self):
38 logger = lldb.formatters.Logger.Logger()
39 self.adjust_for_architecture()
Enrico Granataeb4a4792012-02-23 23:10:27 +000040
Kate Stoneb9c1b512016-09-06 20:57:50 +000041 def num_children(self):
42 logger = lldb.formatters.Logger.Logger()
43 stream = lldb.SBStream()
44 self.valobj.GetExpressionPath(stream)
45 num_children_vo = self.valobj.CreateValueFromExpression(
46 "count", "(int)[" + stream.GetData() + " count]")
47 if num_children_vo.IsValid():
48 return num_children_vo.GetValueAsUnsigned(0)
49 return "<variable is not NSArray>"
Enrico Granataeb4a4792012-02-23 23:10:27 +000050
Enrico Granataeb4a4792012-02-23 23:10:27 +000051# much less functional than the other two cases below
52# just runs code to get to the count and then returns
53# no children
Kate Stoneb9c1b512016-09-06 20:57:50 +000054
55
Enrico Granataeb4a4792012-02-23 23:10:27 +000056class NSArrayCF_SynthProvider:
57
Kate Stoneb9c1b512016-09-06 20:57:50 +000058 def adjust_for_architecture(self):
59 pass
Enrico Granataeb4a4792012-02-23 23:10:27 +000060
Kate Stoneb9c1b512016-09-06 20:57:50 +000061 def __init__(self, valobj, dict, params):
62 logger = lldb.formatters.Logger.Logger()
63 self.valobj = valobj
64 self.sys_params = params
65 if not (self.sys_params.types_cache.ulong):
66 self.sys_params.types_cache.ulong = self.valobj.GetType(
67 ).GetBasicType(lldb.eBasicTypeUnsignedLong)
68 self.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +000069
Kate Stoneb9c1b512016-09-06 20:57:50 +000070 def update(self):
71 logger = lldb.formatters.Logger.Logger()
72 self.adjust_for_architecture()
Enrico Granataeb4a4792012-02-23 23:10:27 +000073
Kate Stoneb9c1b512016-09-06 20:57:50 +000074 def num_children(self):
75 logger = lldb.formatters.Logger.Logger()
76 num_children_vo = self.valobj.CreateChildAtOffset(
77 "count", self.sys_params.cfruntime_size, self.sys_params.types_cache.ulong)
78 return num_children_vo.GetValueAsUnsigned(0)
79
Enrico Granataeb4a4792012-02-23 23:10:27 +000080
Enrico Granataeb4a4792012-02-23 23:10:27 +000081class NSArrayI_SynthProvider:
Enrico Granataeb4a4792012-02-23 23:10:27 +000082
Kate Stoneb9c1b512016-09-06 20:57:50 +000083 def adjust_for_architecture(self):
84 pass
Enrico Granataeb4a4792012-02-23 23:10:27 +000085
Kate Stoneb9c1b512016-09-06 20:57:50 +000086 def __init__(self, valobj, dict, params):
87 logger = lldb.formatters.Logger.Logger()
88 self.valobj = valobj
89 self.sys_params = params
90 if not(self.sys_params.types_cache.long):
91 self.sys_params.types_cache.long = self.valobj.GetType(
92 ).GetBasicType(lldb.eBasicTypeLong)
93 self.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +000094
Kate Stoneb9c1b512016-09-06 20:57:50 +000095 def update(self):
96 logger = lldb.formatters.Logger.Logger()
97 self.adjust_for_architecture()
98
99 # skip the isa pointer and get at the size
100 def num_children(self):
101 logger = lldb.formatters.Logger.Logger()
102 count = self.valobj.CreateChildAtOffset(
103 "count",
104 self.sys_params.pointer_size,
105 self.sys_params.types_cache.long)
106 return count.GetValueAsUnsigned(0)
107
Enrico Granataeb4a4792012-02-23 23:10:27 +0000108
109class NSArrayM_SynthProvider:
Enrico Granataeb4a4792012-02-23 23:10:27 +0000110
Kate Stoneb9c1b512016-09-06 20:57:50 +0000111 def adjust_for_architecture(self):
112 pass
Enrico Granataeb4a4792012-02-23 23:10:27 +0000113
Kate Stoneb9c1b512016-09-06 20:57:50 +0000114 def __init__(self, valobj, dict, params):
115 logger = lldb.formatters.Logger.Logger()
116 self.valobj = valobj
117 self.sys_params = params
118 if not(self.sys_params.types_cache.long):
119 self.sys_params.types_cache.long = self.valobj.GetType(
120 ).GetBasicType(lldb.eBasicTypeLong)
121 self.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +0000122
Kate Stoneb9c1b512016-09-06 20:57:50 +0000123 def update(self):
124 logger = lldb.formatters.Logger.Logger()
125 self.adjust_for_architecture()
126
127 # skip the isa pointer and get at the size
128 def num_children(self):
129 logger = lldb.formatters.Logger.Logger()
130 count = self.valobj.CreateChildAtOffset(
131 "count",
132 self.sys_params.pointer_size,
133 self.sys_params.types_cache.long)
134 return count.GetValueAsUnsigned(0)
Enrico Granataeb4a4792012-02-23 23:10:27 +0000135
136# this is the actual synth provider, but is just a wrapper that checks
137# whether valobj is an instance of __NSArrayI or __NSArrayM and sets up an
Kate Stoneb9c1b512016-09-06 20:57:50 +0000138# appropriate backend layer to do the computations
139
140
Enrico Granataeb4a4792012-02-23 23:10:27 +0000141class NSArray_SynthProvider:
Enrico Granataeb4a4792012-02-23 23:10:27 +0000142
Kate Stoneb9c1b512016-09-06 20:57:50 +0000143 def adjust_for_architecture(self):
144 pass
Enrico Granataeb4a4792012-02-23 23:10:27 +0000145
Kate Stoneb9c1b512016-09-06 20:57:50 +0000146 def __init__(self, valobj, dict):
147 logger = lldb.formatters.Logger.Logger()
148 self.valobj = valobj
149 self.adjust_for_architecture()
150 self.error = False
151 self.wrapper = self.make_wrapper()
152 self.invalid = (self.wrapper is None)
Enrico Granataeb4a4792012-02-23 23:10:27 +0000153
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154 def num_children(self):
155 logger = lldb.formatters.Logger.Logger()
156 if self.wrapper is None:
157 return 0
158 return self.wrapper.num_children()
Enrico Granataeb4a4792012-02-23 23:10:27 +0000159
Kate Stoneb9c1b512016-09-06 20:57:50 +0000160 def update(self):
161 logger = lldb.formatters.Logger.Logger()
162 if self.wrapper is None:
163 return
164 self.wrapper.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +0000165
Kate Stoneb9c1b512016-09-06 20:57:50 +0000166 # this code acts as our defense against NULL and uninitialized
167 # NSArray pointers, which makes it much longer than it would be otherwise
168 def make_wrapper(self):
169 logger = lldb.formatters.Logger.Logger()
170 if self.valobj.GetValueAsUnsigned() == 0:
171 self.error = True
172 return lldb.runtime.objc.objc_runtime.InvalidPointer_Description(
173 True)
174 else:
175 global statistics
176 class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
177 self.valobj, statistics)
178 if wrapper:
179 self.error = True
180 return wrapper
Enrico Granataeb4a4792012-02-23 23:10:27 +0000181
Kate Stoneb9c1b512016-09-06 20:57:50 +0000182 name_string = class_data.class_name()
183
184 logger >> "Class name is " + str(name_string)
185
186 if name_string == '__NSArrayI':
187 wrapper = NSArrayI_SynthProvider(
188 self.valobj, dict, class_data.sys_params)
189 statistics.metric_hit('code_notrun', self.valobj.GetName())
190 elif name_string == '__NSArrayM':
191 wrapper = NSArrayM_SynthProvider(
192 self.valobj, dict, class_data.sys_params)
193 statistics.metric_hit('code_notrun', self.valobj.GetName())
194 elif name_string == '__NSCFArray':
195 wrapper = NSArrayCF_SynthProvider(
196 self.valobj, dict, class_data.sys_params)
197 statistics.metric_hit('code_notrun', self.valobj.GetName())
198 else:
199 wrapper = NSArrayKVC_SynthProvider(
200 self.valobj, dict, class_data.sys_params)
201 statistics.metric_hit(
202 'unknown_class', str(
203 self.valobj.GetName()) + " seen as " + name_string)
204 return wrapper
205
206
207def CFArray_SummaryProvider(valobj, dict):
208 logger = lldb.formatters.Logger.Logger()
209 provider = NSArray_SynthProvider(valobj, dict)
210 if not provider.invalid:
211 if provider.error:
212 return provider.wrapper.message()
213 try:
214 summary = int(provider.num_children())
215 except:
216 summary = None
217 logger >> "provider gave me " + str(summary)
218 if summary is None:
219 summary = '<variable is not NSArray>'
220 elif isinstance(summary, basestring):
221 pass
222 else:
223 # we format it like it were a CFString to make it look the same as
224 # the summary from Xcode
225 summary = '@"' + str(summary) + \
226 (" objects" if summary != 1 else " object") + '"'
227 return summary
228 return 'Summary Unavailable'
229
230
231def __lldb_init_module(debugger, dict):
232 debugger.HandleCommand(
233 "type summary add -F CFArray.CFArray_SummaryProvider NSArray CFArrayRef CFMutableArrayRef")