blob: 4efe76eca59893c4ab99c54f6d6816fce47c621e [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 Granata6d37cc62013-03-19 00:27:22 +00008# example summary provider for NSDate
9# the real summary is now C++ code built into LLDB
Enrico Granata7bc0ec32012-02-29 03:28:49 +000010import lldb
11import ctypes
Enrico Granata28399ad2012-04-25 01:39:27 +000012import lldb.runtime.objc.objc_runtime
13import lldb.formatters.metrics
Enrico Granata7bc0ec32012-02-29 03:28:49 +000014import struct
15import time
16import datetime
Enrico Granata8d5c83f2012-03-02 00:55:53 +000017import CFString
Enrico Granata28399ad2012-04-25 01:39:27 +000018import lldb.formatters.Logger
Enrico Granata7bc0ec32012-02-29 03:28:49 +000019
Enrico Granata28399ad2012-04-25 01:39:27 +000020statistics = lldb.formatters.metrics.Metrics()
Enrico Granata7bc0ec32012-02-29 03:28:49 +000021statistics.add_metric('invalid_isa')
22statistics.add_metric('invalid_pointer')
23statistics.add_metric('unknown_class')
24statistics.add_metric('code_notrun')
25
26# Python promises to start counting time at midnight on Jan 1st on the epoch year
27# hence, all we need to know is the epoch year
28python_epoch = time.gmtime(0).tm_year
29
Kate Stoneb9c1b512016-09-06 20:57:50 +000030osx_epoch = datetime.date(2001, 1, 1).timetuple()
31
Enrico Granata7bc0ec32012-02-29 03:28:49 +000032
33def mkgmtime(t):
Kate Stoneb9c1b512016-09-06 20:57:50 +000034 logger = lldb.formatters.Logger.Logger()
35 return time.mktime(t) - time.timezone
Enrico Granata7bc0ec32012-02-29 03:28:49 +000036
37osx_epoch = mkgmtime(osx_epoch)
38
Kate Stoneb9c1b512016-09-06 20:57:50 +000039
Enrico Granata7bc0ec32012-02-29 03:28:49 +000040def osx_to_python_time(osx):
Kate Stoneb9c1b512016-09-06 20:57:50 +000041 logger = lldb.formatters.Logger.Logger()
42 if python_epoch <= 2001:
43 return osx + osx_epoch
44 else:
45 return osx - osx_epoch
Enrico Granata7bc0ec32012-02-29 03:28:49 +000046
Enrico Granata8c69c962012-03-13 00:25:59 +000047# represent a struct_time as a string in the format used by Xcode
Kate Stoneb9c1b512016-09-06 20:57:50 +000048
49
Enrico Granata8c69c962012-03-13 00:25:59 +000050def xcode_format_time(X):
Kate Stoneb9c1b512016-09-06 20:57:50 +000051 logger = lldb.formatters.Logger.Logger()
52 return time.strftime('%Y-%m-%d %H:%M:%S %Z', X)
Enrico Granata8c69c962012-03-13 00:25:59 +000053
54# represent a count-since-epoch as a string in the format used by Xcode
Kate Stoneb9c1b512016-09-06 20:57:50 +000055
56
Enrico Granata8c69c962012-03-13 00:25:59 +000057def xcode_format_count(X):
Kate Stoneb9c1b512016-09-06 20:57:50 +000058 logger = lldb.formatters.Logger.Logger()
59 return xcode_format_time(time.localtime(X))
Enrico Granata7bc0ec32012-02-29 03:28:49 +000060
61# despite the similary to synthetic children providers, these classes are not
Enrico Granata896cd1d2012-03-01 19:32:33 +000062# trying to provide anything but the summary for NSDate, so they need not
Enrico Granata7bc0ec32012-02-29 03:28:49 +000063# obey the interface specification for synthetic children providers
Kate Stoneb9c1b512016-09-06 20:57:50 +000064
65
Enrico Granata7bc0ec32012-02-29 03:28:49 +000066class NSTaggedDate_SummaryProvider:
Enrico Granata7bc0ec32012-02-29 03:28:49 +000067
Kate Stoneb9c1b512016-09-06 20:57:50 +000068 def adjust_for_architecture(self):
69 pass
Enrico Granata7bc0ec32012-02-29 03:28:49 +000070
Kate Stoneb9c1b512016-09-06 20:57:50 +000071 def __init__(self, valobj, info_bits, data, params):
72 logger = lldb.formatters.Logger.Logger()
73 self.valobj = valobj
74 self.sys_params = params
75 self.update()
76 # NSDate is not using its info_bits for info like NSNumber is
77 # so we need to regroup info_bits and data
78 self.data = ((data << 8) | (info_bits << 4))
Enrico Granata7bc0ec32012-02-29 03:28:49 +000079
Kate Stoneb9c1b512016-09-06 20:57:50 +000080 def update(self):
81 logger = lldb.formatters.Logger.Logger()
82 self.adjust_for_architecture()
83
84 def value(self):
85 logger = lldb.formatters.Logger.Logger()
86 # the value of the date-time object is wrapped into the pointer value
87 # unfortunately, it is made as a time-delta after Jan 1 2001 midnight GMT
88 # while all Python knows about is the "epoch", which is a platform-dependent
89 # year (1970 of *nix) whose Jan 1 at midnight is taken as reference
90 value_double = struct.unpack('d', struct.pack('Q', self.data))[0]
91 if value_double == -63114076800.0:
92 return '0001-12-30 00:00:00 +0000'
93 return xcode_format_count(osx_to_python_time(value_double))
Enrico Granata7bc0ec32012-02-29 03:28:49 +000094
95
96class NSUntaggedDate_SummaryProvider:
Enrico Granata7bc0ec32012-02-29 03:28:49 +000097
Kate Stoneb9c1b512016-09-06 20:57:50 +000098 def adjust_for_architecture(self):
99 pass
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000100
Kate Stoneb9c1b512016-09-06 20:57:50 +0000101 def __init__(self, valobj, params):
102 logger = lldb.formatters.Logger.Logger()
103 self.valobj = valobj
104 self.sys_params = params
105 if not (self.sys_params.types_cache.double):
106 self.sys_params.types_cache.double = self.valobj.GetType(
107 ).GetBasicType(lldb.eBasicTypeDouble)
108 self.update()
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000109
Kate Stoneb9c1b512016-09-06 20:57:50 +0000110 def update(self):
111 logger = lldb.formatters.Logger.Logger()
112 self.adjust_for_architecture()
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000113
Kate Stoneb9c1b512016-09-06 20:57:50 +0000114 def offset(self):
115 logger = lldb.formatters.Logger.Logger()
116 return self.sys_params.pointer_size
117
118 def value(self):
119 logger = lldb.formatters.Logger.Logger()
120 value = self.valobj.CreateChildAtOffset(
121 "value", self.offset(), self.sys_params.types_cache.double)
122 value_double = struct.unpack(
123 'd', struct.pack(
124 'Q', value.GetData().uint64[0]))[0]
125 if value_double == -63114076800.0:
126 return '0001-12-30 00:00:00 +0000'
127 return xcode_format_count(osx_to_python_time(value_double))
128
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000129
Enrico Granata896cd1d2012-03-01 19:32:33 +0000130class NSCalendarDate_SummaryProvider:
Enrico Granata896cd1d2012-03-01 19:32:33 +0000131
Kate Stoneb9c1b512016-09-06 20:57:50 +0000132 def adjust_for_architecture(self):
133 pass
Enrico Granata896cd1d2012-03-01 19:32:33 +0000134
Kate Stoneb9c1b512016-09-06 20:57:50 +0000135 def __init__(self, valobj, params):
136 logger = lldb.formatters.Logger.Logger()
137 self.valobj = valobj
138 self.sys_params = params
139 if not (self.sys_params.types_cache.double):
140 self.sys_params.types_cache.double = self.valobj.GetType(
141 ).GetBasicType(lldb.eBasicTypeDouble)
142 self.update()
Enrico Granata896cd1d2012-03-01 19:32:33 +0000143
Kate Stoneb9c1b512016-09-06 20:57:50 +0000144 def update(self):
145 logger = lldb.formatters.Logger.Logger()
146 self.adjust_for_architecture()
Enrico Granata896cd1d2012-03-01 19:32:33 +0000147
Kate Stoneb9c1b512016-09-06 20:57:50 +0000148 def offset(self):
149 logger = lldb.formatters.Logger.Logger()
150 return 2 * self.sys_params.pointer_size
151
152 def value(self):
153 logger = lldb.formatters.Logger.Logger()
154 value = self.valobj.CreateChildAtOffset(
155 "value", self.offset(), self.sys_params.types_cache.double)
156 value_double = struct.unpack(
157 'd', struct.pack(
158 'Q', value.GetData().uint64[0]))[0]
159 return xcode_format_count(osx_to_python_time(value_double))
160
Enrico Granata896cd1d2012-03-01 19:32:33 +0000161
Enrico Granata8d5c83f2012-03-02 00:55:53 +0000162class NSTimeZoneClass_SummaryProvider:
Enrico Granata8d5c83f2012-03-02 00:55:53 +0000163
Kate Stoneb9c1b512016-09-06 20:57:50 +0000164 def adjust_for_architecture(self):
165 pass
Enrico Granata8d5c83f2012-03-02 00:55:53 +0000166
Kate Stoneb9c1b512016-09-06 20:57:50 +0000167 def __init__(self, valobj, params):
168 logger = lldb.formatters.Logger.Logger()
169 self.valobj = valobj
170 self.sys_params = params
171 if not (self.sys_params.types_cache.voidptr):
172 self.sys_params.types_cache.voidptr = self.valobj.GetType(
173 ).GetBasicType(lldb.eBasicTypeVoid).GetPointerType()
174 self.update()
Enrico Granata8d5c83f2012-03-02 00:55:53 +0000175
Kate Stoneb9c1b512016-09-06 20:57:50 +0000176 def update(self):
177 logger = lldb.formatters.Logger.Logger()
178 self.adjust_for_architecture()
Enrico Granata8d5c83f2012-03-02 00:55:53 +0000179
Kate Stoneb9c1b512016-09-06 20:57:50 +0000180 def offset(self):
181 logger = lldb.formatters.Logger.Logger()
182 return self.sys_params.pointer_size
183
184 def timezone(self):
185 logger = lldb.formatters.Logger.Logger()
186 tz_string = self.valobj.CreateChildAtOffset(
187 "tz_name", self.offset(), self.sys_params.types_cache.voidptr)
188 return CFString.CFString_SummaryProvider(tz_string, None)
189
Enrico Granata896cd1d2012-03-01 19:32:33 +0000190
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000191class NSUnknownDate_SummaryProvider:
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000192
Kate Stoneb9c1b512016-09-06 20:57:50 +0000193 def adjust_for_architecture(self):
194 pass
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000195
Kate Stoneb9c1b512016-09-06 20:57:50 +0000196 def __init__(self, valobj):
197 logger = lldb.formatters.Logger.Logger()
198 self.valobj = valobj
199 self.update()
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000200
Kate Stoneb9c1b512016-09-06 20:57:50 +0000201 def update(self):
202 logger = lldb.formatters.Logger.Logger()
203 self.adjust_for_architecture()
204
205 def value(self):
206 logger = lldb.formatters.Logger.Logger()
207 stream = lldb.SBStream()
208 self.valobj.GetExpressionPath(stream)
209 expr = "(NSString*)[" + stream.GetData() + " description]"
210 num_children_vo = self.valobj.CreateValueFromExpression("str", expr)
211 if num_children_vo.IsValid():
212 return num_children_vo.GetSummary()
213 return '<variable is not NSDate>'
214
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000215
216def GetSummary_Impl(valobj):
Kate Stoneb9c1b512016-09-06 20:57:50 +0000217 logger = lldb.formatters.Logger.Logger()
218 global statistics
219 class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
220 valobj, statistics)
221 if wrapper:
222 return wrapper
Enrico Granata247bd412012-04-02 16:39:29 +0000223
Kate Stoneb9c1b512016-09-06 20:57:50 +0000224 name_string = class_data.class_name()
225 logger >> "class name is: " + str(name_string)
226
227 if name_string == 'NSDate' or name_string == '__NSDate' or name_string == '__NSTaggedDate':
228 if class_data.is_tagged():
229 wrapper = NSTaggedDate_SummaryProvider(
230 valobj, class_data.info_bits(), class_data.value(), class_data.sys_params)
231 statistics.metric_hit('code_notrun', valobj)
232 else:
233 wrapper = NSUntaggedDate_SummaryProvider(
234 valobj, class_data.sys_params)
235 statistics.metric_hit('code_notrun', valobj)
236 elif name_string == 'NSCalendarDate':
237 wrapper = NSCalendarDate_SummaryProvider(valobj, class_data.sys_params)
238 statistics.metric_hit('code_notrun', valobj)
239 elif name_string == '__NSTimeZone':
240 wrapper = NSTimeZoneClass_SummaryProvider(
241 valobj, class_data.sys_params)
242 statistics.metric_hit('code_notrun', valobj)
243 else:
244 wrapper = NSUnknownDate_SummaryProvider(valobj)
245 statistics.metric_hit(
246 'unknown_class',
247 valobj.GetName() +
248 " seen as " +
249 name_string)
250 return wrapper
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000251
252
Kate Stoneb9c1b512016-09-06 20:57:50 +0000253def NSDate_SummaryProvider(valobj, dict):
254 logger = lldb.formatters.Logger.Logger()
255 provider = GetSummary_Impl(valobj)
256 if provider is not None:
257 if isinstance(
258 provider,
259 lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
260 return provider.message()
261 try:
262 summary = provider.value()
263 except:
264 summary = None
265 if summary is None:
266 summary = '<variable is not NSDate>'
267 return str(summary)
268 return 'Summary Unavailable'
Enrico Granata8d5c83f2012-03-02 00:55:53 +0000269
270
Kate Stoneb9c1b512016-09-06 20:57:50 +0000271def NSTimeZone_SummaryProvider(valobj, dict):
272 logger = lldb.formatters.Logger.Logger()
273 provider = GetSummary_Impl(valobj)
274 if provider is not None:
275 if isinstance(
276 provider,
277 lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
278 return provider.message()
279 try:
280 summary = provider.timezone()
281 except:
282 summary = None
283 logger >> "got summary " + str(summary)
284 if summary is None:
285 summary = '<variable is not NSTimeZone>'
286 return str(summary)
287 return 'Summary Unavailable'
Enrico Granata896cd1d2012-03-01 19:32:33 +0000288
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000289
Kate Stoneb9c1b512016-09-06 20:57:50 +0000290def CFAbsoluteTime_SummaryProvider(valobj, dict):
291 logger = lldb.formatters.Logger.Logger()
292 try:
293 value_double = struct.unpack(
294 'd', struct.pack(
295 'Q', valobj.GetData().uint64[0]))[0]
296 return xcode_format_count(osx_to_python_time(value_double))
297 except:
298 return 'Summary Unavailable'
Enrico Granata7bc0ec32012-02-29 03:28:49 +0000299
Kate Stoneb9c1b512016-09-06 20:57:50 +0000300
301def __lldb_init_module(debugger, dict):
302 debugger.HandleCommand(
303 "type summary add -F NSDate.NSDate_SummaryProvider NSDate")
304 debugger.HandleCommand(
305 "type summary add -F NSDate.CFAbsoluteTime_SummaryProvider CFAbsoluteTime")
306 debugger.HandleCommand(
307 "type summary add -F NSDate.NSTimeZone_SummaryProvider NSTimeZone CFTimeZoneRef")