4 Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 See https://llvm.org/LICENSE.txt for license information.
6 SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 # example summary provider for NSDate
9 # the real summary is now C++ code built into LLDB
12 import lldb
.runtime
.objc
.objc_runtime
13 import lldb
.formatters
.metrics
18 import lldb
.formatters
.Logger
20 statistics
= lldb
.formatters
.metrics
.Metrics()
21 statistics
.add_metric("invalid_isa")
22 statistics
.add_metric("invalid_pointer")
23 statistics
.add_metric("unknown_class")
24 statistics
.add_metric("code_notrun")
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
28 python_epoch
= time
.gmtime(0).tm_year
30 osx_epoch
= datetime
.date(2001, 1, 1).timetuple()
34 logger
= lldb
.formatters
.Logger
.Logger()
35 return time
.mktime(t
) - time
.timezone
38 osx_epoch
= mkgmtime(osx_epoch
)
41 def osx_to_python_time(osx
):
42 logger
= lldb
.formatters
.Logger
.Logger()
43 if python_epoch
<= 2001:
44 return osx
+ osx_epoch
46 return osx
- osx_epoch
49 # represent a struct_time as a string in the format used by Xcode
52 def xcode_format_time(X
):
53 logger
= lldb
.formatters
.Logger
.Logger()
54 return time
.strftime("%Y-%m-%d %H:%M:%S %Z", X
)
57 # represent a count-since-epoch as a string in the format used by Xcode
60 def xcode_format_count(X
):
61 logger
= lldb
.formatters
.Logger
.Logger()
62 return xcode_format_time(time
.localtime(X
))
65 # despite the similary to synthetic children providers, these classes are not
66 # trying to provide anything but the summary for NSDate, so they need not
67 # obey the interface specification for synthetic children providers
70 class NSTaggedDate_SummaryProvider
:
71 def adjust_for_architecture(self
):
74 def __init__(self
, valobj
, info_bits
, data
, params
):
75 logger
= lldb
.formatters
.Logger
.Logger()
77 self
.sys_params
= params
79 # NSDate is not using its info_bits for info like NSNumber is
80 # so we need to regroup info_bits and data
81 self
.data
= (data
<< 8) |
(info_bits
<< 4)
84 logger
= lldb
.formatters
.Logger
.Logger()
85 self
.adjust_for_architecture()
88 logger
= lldb
.formatters
.Logger
.Logger()
89 # the value of the date-time object is wrapped into the pointer value
90 # unfortunately, it is made as a time-delta after Jan 1 2001 midnight GMT
91 # while all Python knows about is the "epoch", which is a platform-dependent
92 # year (1970 of *nix) whose Jan 1 at midnight is taken as reference
93 value_double
= struct
.unpack("d", struct
.pack("Q", self
.data
))[0]
94 if value_double
== -63114076800.0:
95 return "0001-12-30 00:00:00 +0000"
96 return xcode_format_count(osx_to_python_time(value_double
))
99 class NSUntaggedDate_SummaryProvider
:
100 def adjust_for_architecture(self
):
103 def __init__(self
, valobj
, params
):
104 logger
= lldb
.formatters
.Logger
.Logger()
106 self
.sys_params
= params
107 if not (self
.sys_params
.types_cache
.double
):
108 self
.sys_params
.types_cache
.double
= self
.valobj
.GetType().GetBasicType(
109 lldb
.eBasicTypeDouble
114 logger
= lldb
.formatters
.Logger
.Logger()
115 self
.adjust_for_architecture()
118 logger
= lldb
.formatters
.Logger
.Logger()
119 return self
.sys_params
.pointer_size
122 logger
= lldb
.formatters
.Logger
.Logger()
123 value
= self
.valobj
.CreateChildAtOffset(
124 "value", self
.offset(), self
.sys_params
.types_cache
.double
126 value_double
= struct
.unpack("d", struct
.pack("Q", value
.GetData().uint64
[0]))[
129 if value_double
== -63114076800.0:
130 return "0001-12-30 00:00:00 +0000"
131 return xcode_format_count(osx_to_python_time(value_double
))
134 class NSCalendarDate_SummaryProvider
:
135 def adjust_for_architecture(self
):
138 def __init__(self
, valobj
, params
):
139 logger
= lldb
.formatters
.Logger
.Logger()
141 self
.sys_params
= params
142 if not (self
.sys_params
.types_cache
.double
):
143 self
.sys_params
.types_cache
.double
= self
.valobj
.GetType().GetBasicType(
144 lldb
.eBasicTypeDouble
149 logger
= lldb
.formatters
.Logger
.Logger()
150 self
.adjust_for_architecture()
153 logger
= lldb
.formatters
.Logger
.Logger()
154 return 2 * self
.sys_params
.pointer_size
157 logger
= lldb
.formatters
.Logger
.Logger()
158 value
= self
.valobj
.CreateChildAtOffset(
159 "value", self
.offset(), self
.sys_params
.types_cache
.double
161 value_double
= struct
.unpack("d", struct
.pack("Q", value
.GetData().uint64
[0]))[
164 return xcode_format_count(osx_to_python_time(value_double
))
167 class NSTimeZoneClass_SummaryProvider
:
168 def adjust_for_architecture(self
):
171 def __init__(self
, valobj
, params
):
172 logger
= lldb
.formatters
.Logger
.Logger()
174 self
.sys_params
= params
175 if not (self
.sys_params
.types_cache
.voidptr
):
176 self
.sys_params
.types_cache
.voidptr
= (
177 self
.valobj
.GetType().GetBasicType(lldb
.eBasicTypeVoid
).GetPointerType()
182 logger
= lldb
.formatters
.Logger
.Logger()
183 self
.adjust_for_architecture()
186 logger
= lldb
.formatters
.Logger
.Logger()
187 return self
.sys_params
.pointer_size
190 logger
= lldb
.formatters
.Logger
.Logger()
191 tz_string
= self
.valobj
.CreateChildAtOffset(
192 "tz_name", self
.offset(), self
.sys_params
.types_cache
.voidptr
194 return CFString
.CFString_SummaryProvider(tz_string
, None)
197 class NSUnknownDate_SummaryProvider
:
198 def adjust_for_architecture(self
):
201 def __init__(self
, valobj
):
202 logger
= lldb
.formatters
.Logger
.Logger()
207 logger
= lldb
.formatters
.Logger
.Logger()
208 self
.adjust_for_architecture()
211 logger
= lldb
.formatters
.Logger
.Logger()
212 stream
= lldb
.SBStream()
213 self
.valobj
.GetExpressionPath(stream
)
214 expr
= "(NSString*)[" + stream
.GetData() + " description]"
215 num_children_vo
= self
.valobj
.CreateValueFromExpression("str", expr
)
216 if num_children_vo
.IsValid():
217 return num_children_vo
.GetSummary()
218 return "<variable is not NSDate>"
221 def GetSummary_Impl(valobj
):
222 logger
= lldb
.formatters
.Logger
.Logger()
227 ) = lldb
.runtime
.objc
.objc_runtime
.Utilities
.prepare_class_detection(
233 name_string
= class_data
.class_name()
234 logger
>> "class name is: " + str(name_string
)
237 name_string
== "NSDate"
238 or name_string
== "__NSDate"
239 or name_string
== "__NSTaggedDate"
241 if class_data
.is_tagged():
242 wrapper
= NSTaggedDate_SummaryProvider(
244 class_data
.info_bits(),
246 class_data
.sys_params
,
248 statistics
.metric_hit("code_notrun", valobj
)
250 wrapper
= NSUntaggedDate_SummaryProvider(valobj
, class_data
.sys_params
)
251 statistics
.metric_hit("code_notrun", valobj
)
252 elif name_string
== "NSCalendarDate":
253 wrapper
= NSCalendarDate_SummaryProvider(valobj
, class_data
.sys_params
)
254 statistics
.metric_hit("code_notrun", valobj
)
255 elif name_string
== "__NSTimeZone":
256 wrapper
= NSTimeZoneClass_SummaryProvider(valobj
, class_data
.sys_params
)
257 statistics
.metric_hit("code_notrun", valobj
)
259 wrapper
= NSUnknownDate_SummaryProvider(valobj
)
260 statistics
.metric_hit(
261 "unknown_class", valobj
.GetName() + " seen as " + name_string
266 def NSDate_SummaryProvider(valobj
, dict):
267 logger
= lldb
.formatters
.Logger
.Logger()
268 provider
= GetSummary_Impl(valobj
)
269 if provider
is not None:
271 provider
, lldb
.runtime
.objc
.objc_runtime
.SpecialSituation_Description
273 return provider
.message()
275 summary
= provider
.value()
279 summary
= "<variable is not NSDate>"
281 return "Summary Unavailable"
284 def NSTimeZone_SummaryProvider(valobj
, dict):
285 logger
= lldb
.formatters
.Logger
.Logger()
286 provider
= GetSummary_Impl(valobj
)
287 if provider
is not None:
289 provider
, lldb
.runtime
.objc
.objc_runtime
.SpecialSituation_Description
291 return provider
.message()
293 summary
= provider
.timezone()
296 logger
>> "got summary " + str(summary
)
298 summary
= "<variable is not NSTimeZone>"
300 return "Summary Unavailable"
303 def CFAbsoluteTime_SummaryProvider(valobj
, dict):
304 logger
= lldb
.formatters
.Logger
.Logger()
306 value_double
= struct
.unpack("d", struct
.pack("Q", valobj
.GetData().uint64
[0]))[
309 return xcode_format_count(osx_to_python_time(value_double
))
311 return "Summary Unavailable"
314 def __lldb_init_module(debugger
, dict):
315 debugger
.HandleCommand("type summary add -F NSDate.NSDate_SummaryProvider NSDate")
316 debugger
.HandleCommand(
317 "type summary add -F NSDate.CFAbsoluteTime_SummaryProvider CFAbsoluteTime"
319 debugger
.HandleCommand(
320 "type summary add -F NSDate.NSTimeZone_SummaryProvider NSTimeZone CFTimeZoneRef"