blob: 3225ea95ded668299cc3459149b36d6fe3d69bcd [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 NSNumber
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
Enrico Granataeb4a4792012-02-23 23:10:27 +000014import struct
Enrico Granata28399ad2012-04-25 01:39:27 +000015import lldb.formatters.Logger
Enrico Granataeb4a4792012-02-23 23:10:27 +000016
Enrico Granata28399ad2012-04-25 01:39:27 +000017statistics = lldb.formatters.metrics.Metrics()
Enrico Granataeb4a4792012-02-23 23:10:27 +000018statistics.add_metric('invalid_isa')
19statistics.add_metric('invalid_pointer')
20statistics.add_metric('unknown_class')
21statistics.add_metric('code_notrun')
22
23# despite the similary to synthetic children providers, these classes are not
24# trying to provide anything but the port number of an NSNumber, so they need not
25# obey the interface specification for synthetic children providers
Kate Stoneb9c1b512016-09-06 20:57:50 +000026
27
Enrico Granataeb4a4792012-02-23 23:10:27 +000028class NSTaggedNumber_SummaryProvider:
Enrico Granataeb4a4792012-02-23 23:10:27 +000029
Kate Stoneb9c1b512016-09-06 20:57:50 +000030 def adjust_for_architecture(self):
31 pass
Enrico Granataeb4a4792012-02-23 23:10:27 +000032
Kate Stoneb9c1b512016-09-06 20:57:50 +000033 def __init__(self, valobj, info_bits, data, params):
34 logger = lldb.formatters.Logger.Logger()
35 self.valobj = valobj
36 self.sys_params = params
37 self.info_bits = info_bits
38 self.data = data
39 self.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +000040
Kate Stoneb9c1b512016-09-06 20:57:50 +000041 def update(self):
42 logger = lldb.formatters.Logger.Logger()
43 self.adjust_for_architecture()
44
45 def value(self):
46 logger = lldb.formatters.Logger.Logger()
47 # in spite of the plenty of types made available by the public NSNumber API
48 # only a bunch of these are actually used in the internal implementation
49 # unfortunately, the original type information appears to be lost
50 # so we try to at least recover the proper magnitude of the data
51 if self.info_bits == 0:
52 return '(char)' + \
53 str(ord(ctypes.c_char(chr(self.data % 256)).value))
54 if self.info_bits == 4:
55 return '(short)' + \
56 str(ctypes.c_short(self.data % (256 * 256)).value)
57 if self.info_bits == 8:
58 return '(int)' + str(ctypes.c_int(self.data %
59 (256 * 256 * 256 * 256)).value)
60 if self.info_bits == 12:
61 return '(long)' + str(ctypes.c_long(self.data).value)
62 else:
63 return 'unexpected value:(info=' + str(self.info_bits) + \
64 ", value = " + str(self.data) + ')'
Enrico Granataeb4a4792012-02-23 23:10:27 +000065
66
67class NSUntaggedNumber_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.char):
77 self.sys_params.types_cache.char = self.valobj.GetType(
78 ).GetBasicType(lldb.eBasicTypeChar)
79 if not(self.sys_params.types_cache.short):
80 self.sys_params.types_cache.short = self.valobj.GetType(
81 ).GetBasicType(lldb.eBasicTypeShort)
82 if not(self.sys_params.types_cache.ushort):
83 self.sys_params.types_cache.ushort = self.valobj.GetType(
84 ).GetBasicType(lldb.eBasicTypeUnsignedShort)
85 if not(self.sys_params.types_cache.int):
86 self.sys_params.types_cache.int = self.valobj.GetType().GetBasicType(lldb.eBasicTypeInt)
87 if not(self.sys_params.types_cache.long):
88 self.sys_params.types_cache.long = self.valobj.GetType(
89 ).GetBasicType(lldb.eBasicTypeLong)
90 if not(self.sys_params.types_cache.ulong):
91 self.sys_params.types_cache.ulong = self.valobj.GetType(
92 ).GetBasicType(lldb.eBasicTypeUnsignedLong)
93 if not(self.sys_params.types_cache.longlong):
94 self.sys_params.types_cache.longlong = self.valobj.GetType(
95 ).GetBasicType(lldb.eBasicTypeLongLong)
96 if not(self.sys_params.types_cache.ulonglong):
97 self.sys_params.types_cache.ulonglong = self.valobj.GetType(
98 ).GetBasicType(lldb.eBasicTypeUnsignedLongLong)
99 if not(self.sys_params.types_cache.float):
100 self.sys_params.types_cache.float = self.valobj.GetType(
101 ).GetBasicType(lldb.eBasicTypeFloat)
102 if not(self.sys_params.types_cache.double):
103 self.sys_params.types_cache.double = self.valobj.GetType(
104 ).GetBasicType(lldb.eBasicTypeDouble)
105 self.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +0000106
Kate Stoneb9c1b512016-09-06 20:57:50 +0000107 def update(self):
108 logger = lldb.formatters.Logger.Logger()
109 self.adjust_for_architecture()
110
111 def value(self):
112 logger = lldb.formatters.Logger.Logger()
113 global statistics
114 # we need to skip the ISA, then the next byte tells us what to read
115 # we then skip one other full pointer worth of data and then fetch the contents
116 # if we are fetching an int64 value, one more pointer must be skipped
117 # to get at our data
118 data_type_vo = self.valobj.CreateChildAtOffset(
119 "dt", self.sys_params.pointer_size, self.sys_params.types_cache.char)
120 data_type = ((data_type_vo.GetValueAsUnsigned(0) % 256) & 0x1F)
121 data_offset = 2 * self.sys_params.pointer_size
122 if data_type == 0B00001:
123 data_vo = self.valobj.CreateChildAtOffset(
124 "data", data_offset, self.sys_params.types_cache.char)
125 statistics.metric_hit('code_notrun', self.valobj)
126 return '(char)' + \
127 str(ord(ctypes.c_char(chr(data_vo.GetValueAsUnsigned(0))).value))
128 elif data_type == 0B0010:
129 data_vo = self.valobj.CreateChildAtOffset(
130 "data", data_offset, self.sys_params.types_cache.short)
131 statistics.metric_hit('code_notrun', self.valobj)
132 return '(short)' + str(
133 ctypes.c_short(
134 data_vo.GetValueAsUnsigned(0) %
135 (256 * 256)).value)
136 # IF tagged pointers are possible on 32bit+v2 runtime
137 # (of which the only existing instance should be iOS)
138 # then values of this type might be tagged
139 elif data_type == 0B0011:
140 data_vo = self.valobj.CreateChildAtOffset(
141 "data", data_offset, self.sys_params.types_cache.int)
142 statistics.metric_hit('code_notrun', self.valobj)
143 return '(int)' + str(ctypes.c_int(data_vo.GetValueAsUnsigned(0) %
144 (256 * 256 * 256 * 256)).value)
145 # apparently, on is_64_bit architectures, these are the only values that will ever
146 # be represented by a non tagged pointers
147 elif data_type == 0B10001:
148 data_offset = data_offset + 8 # 8 is needed even if we are on 32bit
149 data_vo = self.valobj.CreateChildAtOffset(
150 "data", data_offset, self.sys_params.types_cache.longlong)
151 statistics.metric_hit('code_notrun', self.valobj)
152 return '(long)' + \
153 str(ctypes.c_long(data_vo.GetValueAsUnsigned(0)).value)
154 elif data_type == 0B0100:
155 if self.sys_params.is_64_bit:
156 data_offset = data_offset + self.sys_params.pointer_size
157 data_vo = self.valobj.CreateChildAtOffset(
158 "data", data_offset, self.sys_params.types_cache.longlong)
159 statistics.metric_hit('code_notrun', self.valobj)
160 return '(long)' + \
161 str(ctypes.c_long(data_vo.GetValueAsUnsigned(0)).value)
162 elif data_type == 0B0101:
163 data_vo = self.valobj.CreateChildAtOffset(
164 "data", data_offset, self.sys_params.types_cache.longlong)
165 data_plain = int(
166 str(data_vo.GetValueAsUnsigned(0) & 0x00000000FFFFFFFF))
167 packed = struct.pack('I', data_plain)
168 data_float = struct.unpack('f', packed)[0]
169 statistics.metric_hit('code_notrun', self.valobj)
170 return '(float)' + str(data_float)
171 elif data_type == 0B0110:
172 data_vo = self.valobj.CreateChildAtOffset(
173 "data", data_offset, self.sys_params.types_cache.longlong)
174 data_plain = data_vo.GetValueAsUnsigned(0)
175 data_double = struct.unpack('d', struct.pack('Q', data_plain))[0]
176 statistics.metric_hit('code_notrun', self.valobj)
177 return '(double)' + str(data_double)
178 statistics.metric_hit(
179 'unknown_class', str(
180 valobj.GetName()) + " had unknown data_type " + str(data_type))
181 return 'unexpected: dt = ' + str(data_type)
Enrico Granataeb4a4792012-02-23 23:10:27 +0000182
183
184class NSUnknownNumber_SummaryProvider:
Enrico Granataeb4a4792012-02-23 23:10:27 +0000185
Kate Stoneb9c1b512016-09-06 20:57:50 +0000186 def adjust_for_architecture(self):
187 pass
Enrico Granataeb4a4792012-02-23 23:10:27 +0000188
Kate Stoneb9c1b512016-09-06 20:57:50 +0000189 def __init__(self, valobj, params):
190 logger = lldb.formatters.Logger.Logger()
191 self.valobj = valobj
192 self.sys_params = params
193 self.update()
Enrico Granataeb4a4792012-02-23 23:10:27 +0000194
Kate Stoneb9c1b512016-09-06 20:57:50 +0000195 def update(self):
196 logger = lldb.formatters.Logger.Logger()
197 self.adjust_for_architecture()
198
199 def value(self):
200 logger = lldb.formatters.Logger.Logger()
201 stream = lldb.SBStream()
202 self.valobj.GetExpressionPath(stream)
203 expr = "(NSString*)[" + stream.GetData() + " stringValue]"
204 num_children_vo = self.valobj.CreateValueFromExpression("str", expr)
205 if num_children_vo.IsValid():
206 return num_children_vo.GetSummary()
207 return '<variable is not NSNumber>'
208
Enrico Granataeb4a4792012-02-23 23:10:27 +0000209
210def GetSummary_Impl(valobj):
Kate Stoneb9c1b512016-09-06 20:57:50 +0000211 logger = lldb.formatters.Logger.Logger()
212 global statistics
213 class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
214 valobj, statistics)
215 if wrapper:
216 return wrapper
Enrico Granata247bd412012-04-02 16:39:29 +0000217
Kate Stoneb9c1b512016-09-06 20:57:50 +0000218 name_string = class_data.class_name()
219 logger >> "class name is: " + str(name_string)
220
221 if name_string == 'NSNumber' or name_string == '__NSCFNumber':
222 if class_data.is_tagged():
223 wrapper = NSTaggedNumber_SummaryProvider(
224 valobj, class_data.info_bits(), class_data.value(), class_data.sys_params)
225 statistics.metric_hit('code_notrun', valobj)
226 else:
227 # the wrapper might be unable to decipher what is into the NSNumber
228 # and then have to run code on it
229 wrapper = NSUntaggedNumber_SummaryProvider(
230 valobj, class_data.sys_params)
231 else:
232 wrapper = NSUnknownNumber_SummaryProvider(
233 valobj, class_data.sys_params)
234 statistics.metric_hit(
235 'unknown_class',
236 valobj.GetName() +
237 " seen as " +
238 name_string)
239 return wrapper
Enrico Granataeb4a4792012-02-23 23:10:27 +0000240
241
Kate Stoneb9c1b512016-09-06 20:57:50 +0000242def NSNumber_SummaryProvider(valobj, dict):
243 logger = lldb.formatters.Logger.Logger()
244 provider = GetSummary_Impl(valobj)
245 if provider is not None:
246 if isinstance(
247 provider,
248 lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
249 return provider.message()
250 try:
251 summary = provider.value()
252 except Exception as foo:
253 print foo
Enrico Granata811e9052012-07-13 18:53:14 +0000254# except:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000255 summary = None
256 logger >> "got summary " + str(summary)
257 if summary is None:
258 summary = '<variable is not NSNumber>'
259 return str(summary)
260 return 'Summary Unavailable'
Enrico Granataeb4a4792012-02-23 23:10:27 +0000261
262
Kate Stoneb9c1b512016-09-06 20:57:50 +0000263def __lldb_init_module(debugger, dict):
264 debugger.HandleCommand(
265 "type summary add -F NSNumber.NSNumber_SummaryProvider NSNumber")
266 debugger.HandleCommand(
267 "type summary add -F NSNumber.NSNumber_SummaryProvider __NSCFBoolean")
268 debugger.HandleCommand(
269 "type summary add -F NSNumber.NSNumber_SummaryProvider __NSCFNumber")