xref: /openbsd-src/gnu/llvm/lldb/examples/summaries/cocoa/NSDate.py (revision 061da546b983eb767bad15e67af1174fb0bcf31c)
1*061da546Spatrick"""
2*061da546SpatrickLLDB AppKit formatters
3*061da546Spatrick
4*061da546SpatrickPart of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5*061da546SpatrickSee https://llvm.org/LICENSE.txt for license information.
6*061da546SpatrickSPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7*061da546Spatrick"""
8*061da546Spatrick# example summary provider for NSDate
9*061da546Spatrick# the real summary is now C++ code built into LLDB
10*061da546Spatrickimport lldb
11*061da546Spatrickimport ctypes
12*061da546Spatrickimport lldb.runtime.objc.objc_runtime
13*061da546Spatrickimport lldb.formatters.metrics
14*061da546Spatrickimport struct
15*061da546Spatrickimport time
16*061da546Spatrickimport datetime
17*061da546Spatrickimport CFString
18*061da546Spatrickimport lldb.formatters.Logger
19*061da546Spatrick
20*061da546Spatrickstatistics = lldb.formatters.metrics.Metrics()
21*061da546Spatrickstatistics.add_metric('invalid_isa')
22*061da546Spatrickstatistics.add_metric('invalid_pointer')
23*061da546Spatrickstatistics.add_metric('unknown_class')
24*061da546Spatrickstatistics.add_metric('code_notrun')
25*061da546Spatrick
26*061da546Spatrick# Python promises to start counting time at midnight on Jan 1st on the epoch year
27*061da546Spatrick# hence, all we need to know is the epoch year
28*061da546Spatrickpython_epoch = time.gmtime(0).tm_year
29*061da546Spatrick
30*061da546Spatrickosx_epoch = datetime.date(2001, 1, 1).timetuple()
31*061da546Spatrick
32*061da546Spatrick
33*061da546Spatrickdef mkgmtime(t):
34*061da546Spatrick    logger = lldb.formatters.Logger.Logger()
35*061da546Spatrick    return time.mktime(t) - time.timezone
36*061da546Spatrick
37*061da546Spatrickosx_epoch = mkgmtime(osx_epoch)
38*061da546Spatrick
39*061da546Spatrick
40*061da546Spatrickdef osx_to_python_time(osx):
41*061da546Spatrick    logger = lldb.formatters.Logger.Logger()
42*061da546Spatrick    if python_epoch <= 2001:
43*061da546Spatrick        return osx + osx_epoch
44*061da546Spatrick    else:
45*061da546Spatrick        return osx - osx_epoch
46*061da546Spatrick
47*061da546Spatrick# represent a struct_time as a string in the format used by Xcode
48*061da546Spatrick
49*061da546Spatrick
50*061da546Spatrickdef xcode_format_time(X):
51*061da546Spatrick    logger = lldb.formatters.Logger.Logger()
52*061da546Spatrick    return time.strftime('%Y-%m-%d %H:%M:%S %Z', X)
53*061da546Spatrick
54*061da546Spatrick# represent a count-since-epoch as a string in the format used by Xcode
55*061da546Spatrick
56*061da546Spatrick
57*061da546Spatrickdef xcode_format_count(X):
58*061da546Spatrick    logger = lldb.formatters.Logger.Logger()
59*061da546Spatrick    return xcode_format_time(time.localtime(X))
60*061da546Spatrick
61*061da546Spatrick# despite the similary to synthetic children providers, these classes are not
62*061da546Spatrick# trying to provide anything but the summary for NSDate, so they need not
63*061da546Spatrick# obey the interface specification for synthetic children providers
64*061da546Spatrick
65*061da546Spatrick
66*061da546Spatrickclass NSTaggedDate_SummaryProvider:
67*061da546Spatrick
68*061da546Spatrick    def adjust_for_architecture(self):
69*061da546Spatrick        pass
70*061da546Spatrick
71*061da546Spatrick    def __init__(self, valobj, info_bits, data, params):
72*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
73*061da546Spatrick        self.valobj = valobj
74*061da546Spatrick        self.sys_params = params
75*061da546Spatrick        self.update()
76*061da546Spatrick        # NSDate is not using its info_bits for info like NSNumber is
77*061da546Spatrick        # so we need to regroup info_bits and data
78*061da546Spatrick        self.data = ((data << 8) | (info_bits << 4))
79*061da546Spatrick
80*061da546Spatrick    def update(self):
81*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
82*061da546Spatrick        self.adjust_for_architecture()
83*061da546Spatrick
84*061da546Spatrick    def value(self):
85*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
86*061da546Spatrick        # the value of the date-time object is wrapped into the pointer value
87*061da546Spatrick        # unfortunately, it is made as a time-delta after Jan 1 2001 midnight GMT
88*061da546Spatrick        # while all Python knows about is the "epoch", which is a platform-dependent
89*061da546Spatrick        # year (1970 of *nix) whose Jan 1 at midnight is taken as reference
90*061da546Spatrick        value_double = struct.unpack('d', struct.pack('Q', self.data))[0]
91*061da546Spatrick        if value_double == -63114076800.0:
92*061da546Spatrick            return '0001-12-30 00:00:00 +0000'
93*061da546Spatrick        return xcode_format_count(osx_to_python_time(value_double))
94*061da546Spatrick
95*061da546Spatrick
96*061da546Spatrickclass NSUntaggedDate_SummaryProvider:
97*061da546Spatrick
98*061da546Spatrick    def adjust_for_architecture(self):
99*061da546Spatrick        pass
100*061da546Spatrick
101*061da546Spatrick    def __init__(self, valobj, params):
102*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
103*061da546Spatrick        self.valobj = valobj
104*061da546Spatrick        self.sys_params = params
105*061da546Spatrick        if not (self.sys_params.types_cache.double):
106*061da546Spatrick            self.sys_params.types_cache.double = self.valobj.GetType(
107*061da546Spatrick            ).GetBasicType(lldb.eBasicTypeDouble)
108*061da546Spatrick        self.update()
109*061da546Spatrick
110*061da546Spatrick    def update(self):
111*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
112*061da546Spatrick        self.adjust_for_architecture()
113*061da546Spatrick
114*061da546Spatrick    def offset(self):
115*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
116*061da546Spatrick        return self.sys_params.pointer_size
117*061da546Spatrick
118*061da546Spatrick    def value(self):
119*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
120*061da546Spatrick        value = self.valobj.CreateChildAtOffset(
121*061da546Spatrick            "value", self.offset(), self.sys_params.types_cache.double)
122*061da546Spatrick        value_double = struct.unpack(
123*061da546Spatrick            'd', struct.pack(
124*061da546Spatrick                'Q', value.GetData().uint64[0]))[0]
125*061da546Spatrick        if value_double == -63114076800.0:
126*061da546Spatrick            return '0001-12-30 00:00:00 +0000'
127*061da546Spatrick        return xcode_format_count(osx_to_python_time(value_double))
128*061da546Spatrick
129*061da546Spatrick
130*061da546Spatrickclass NSCalendarDate_SummaryProvider:
131*061da546Spatrick
132*061da546Spatrick    def adjust_for_architecture(self):
133*061da546Spatrick        pass
134*061da546Spatrick
135*061da546Spatrick    def __init__(self, valobj, params):
136*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
137*061da546Spatrick        self.valobj = valobj
138*061da546Spatrick        self.sys_params = params
139*061da546Spatrick        if not (self.sys_params.types_cache.double):
140*061da546Spatrick            self.sys_params.types_cache.double = self.valobj.GetType(
141*061da546Spatrick            ).GetBasicType(lldb.eBasicTypeDouble)
142*061da546Spatrick        self.update()
143*061da546Spatrick
144*061da546Spatrick    def update(self):
145*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
146*061da546Spatrick        self.adjust_for_architecture()
147*061da546Spatrick
148*061da546Spatrick    def offset(self):
149*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
150*061da546Spatrick        return 2 * self.sys_params.pointer_size
151*061da546Spatrick
152*061da546Spatrick    def value(self):
153*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
154*061da546Spatrick        value = self.valobj.CreateChildAtOffset(
155*061da546Spatrick            "value", self.offset(), self.sys_params.types_cache.double)
156*061da546Spatrick        value_double = struct.unpack(
157*061da546Spatrick            'd', struct.pack(
158*061da546Spatrick                'Q', value.GetData().uint64[0]))[0]
159*061da546Spatrick        return xcode_format_count(osx_to_python_time(value_double))
160*061da546Spatrick
161*061da546Spatrick
162*061da546Spatrickclass NSTimeZoneClass_SummaryProvider:
163*061da546Spatrick
164*061da546Spatrick    def adjust_for_architecture(self):
165*061da546Spatrick        pass
166*061da546Spatrick
167*061da546Spatrick    def __init__(self, valobj, params):
168*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
169*061da546Spatrick        self.valobj = valobj
170*061da546Spatrick        self.sys_params = params
171*061da546Spatrick        if not (self.sys_params.types_cache.voidptr):
172*061da546Spatrick            self.sys_params.types_cache.voidptr = self.valobj.GetType(
173*061da546Spatrick            ).GetBasicType(lldb.eBasicTypeVoid).GetPointerType()
174*061da546Spatrick        self.update()
175*061da546Spatrick
176*061da546Spatrick    def update(self):
177*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
178*061da546Spatrick        self.adjust_for_architecture()
179*061da546Spatrick
180*061da546Spatrick    def offset(self):
181*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
182*061da546Spatrick        return self.sys_params.pointer_size
183*061da546Spatrick
184*061da546Spatrick    def timezone(self):
185*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
186*061da546Spatrick        tz_string = self.valobj.CreateChildAtOffset(
187*061da546Spatrick            "tz_name", self.offset(), self.sys_params.types_cache.voidptr)
188*061da546Spatrick        return CFString.CFString_SummaryProvider(tz_string, None)
189*061da546Spatrick
190*061da546Spatrick
191*061da546Spatrickclass NSUnknownDate_SummaryProvider:
192*061da546Spatrick
193*061da546Spatrick    def adjust_for_architecture(self):
194*061da546Spatrick        pass
195*061da546Spatrick
196*061da546Spatrick    def __init__(self, valobj):
197*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
198*061da546Spatrick        self.valobj = valobj
199*061da546Spatrick        self.update()
200*061da546Spatrick
201*061da546Spatrick    def update(self):
202*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
203*061da546Spatrick        self.adjust_for_architecture()
204*061da546Spatrick
205*061da546Spatrick    def value(self):
206*061da546Spatrick        logger = lldb.formatters.Logger.Logger()
207*061da546Spatrick        stream = lldb.SBStream()
208*061da546Spatrick        self.valobj.GetExpressionPath(stream)
209*061da546Spatrick        expr = "(NSString*)[" + stream.GetData() + " description]"
210*061da546Spatrick        num_children_vo = self.valobj.CreateValueFromExpression("str", expr)
211*061da546Spatrick        if num_children_vo.IsValid():
212*061da546Spatrick            return num_children_vo.GetSummary()
213*061da546Spatrick        return '<variable is not NSDate>'
214*061da546Spatrick
215*061da546Spatrick
216*061da546Spatrickdef GetSummary_Impl(valobj):
217*061da546Spatrick    logger = lldb.formatters.Logger.Logger()
218*061da546Spatrick    global statistics
219*061da546Spatrick    class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
220*061da546Spatrick        valobj, statistics)
221*061da546Spatrick    if wrapper:
222*061da546Spatrick        return wrapper
223*061da546Spatrick
224*061da546Spatrick    name_string = class_data.class_name()
225*061da546Spatrick    logger >> "class name is: " + str(name_string)
226*061da546Spatrick
227*061da546Spatrick    if name_string == 'NSDate' or name_string == '__NSDate' or name_string == '__NSTaggedDate':
228*061da546Spatrick        if class_data.is_tagged():
229*061da546Spatrick            wrapper = NSTaggedDate_SummaryProvider(
230*061da546Spatrick                valobj, class_data.info_bits(), class_data.value(), class_data.sys_params)
231*061da546Spatrick            statistics.metric_hit('code_notrun', valobj)
232*061da546Spatrick        else:
233*061da546Spatrick            wrapper = NSUntaggedDate_SummaryProvider(
234*061da546Spatrick                valobj, class_data.sys_params)
235*061da546Spatrick            statistics.metric_hit('code_notrun', valobj)
236*061da546Spatrick    elif name_string == 'NSCalendarDate':
237*061da546Spatrick        wrapper = NSCalendarDate_SummaryProvider(valobj, class_data.sys_params)
238*061da546Spatrick        statistics.metric_hit('code_notrun', valobj)
239*061da546Spatrick    elif name_string == '__NSTimeZone':
240*061da546Spatrick        wrapper = NSTimeZoneClass_SummaryProvider(
241*061da546Spatrick            valobj, class_data.sys_params)
242*061da546Spatrick        statistics.metric_hit('code_notrun', valobj)
243*061da546Spatrick    else:
244*061da546Spatrick        wrapper = NSUnknownDate_SummaryProvider(valobj)
245*061da546Spatrick        statistics.metric_hit(
246*061da546Spatrick            'unknown_class',
247*061da546Spatrick            valobj.GetName() +
248*061da546Spatrick            " seen as " +
249*061da546Spatrick            name_string)
250*061da546Spatrick    return wrapper
251*061da546Spatrick
252*061da546Spatrick
253*061da546Spatrickdef NSDate_SummaryProvider(valobj, dict):
254*061da546Spatrick    logger = lldb.formatters.Logger.Logger()
255*061da546Spatrick    provider = GetSummary_Impl(valobj)
256*061da546Spatrick    if provider is not None:
257*061da546Spatrick        if isinstance(
258*061da546Spatrick                provider,
259*061da546Spatrick                lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
260*061da546Spatrick            return provider.message()
261*061da546Spatrick        try:
262*061da546Spatrick            summary = provider.value()
263*061da546Spatrick        except:
264*061da546Spatrick            summary = None
265*061da546Spatrick        if summary is None:
266*061da546Spatrick            summary = '<variable is not NSDate>'
267*061da546Spatrick        return str(summary)
268*061da546Spatrick    return 'Summary Unavailable'
269*061da546Spatrick
270*061da546Spatrick
271*061da546Spatrickdef NSTimeZone_SummaryProvider(valobj, dict):
272*061da546Spatrick    logger = lldb.formatters.Logger.Logger()
273*061da546Spatrick    provider = GetSummary_Impl(valobj)
274*061da546Spatrick    if provider is not None:
275*061da546Spatrick        if isinstance(
276*061da546Spatrick                provider,
277*061da546Spatrick                lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
278*061da546Spatrick            return provider.message()
279*061da546Spatrick        try:
280*061da546Spatrick            summary = provider.timezone()
281*061da546Spatrick        except:
282*061da546Spatrick            summary = None
283*061da546Spatrick        logger >> "got summary " + str(summary)
284*061da546Spatrick        if summary is None:
285*061da546Spatrick            summary = '<variable is not NSTimeZone>'
286*061da546Spatrick        return str(summary)
287*061da546Spatrick    return 'Summary Unavailable'
288*061da546Spatrick
289*061da546Spatrick
290*061da546Spatrickdef CFAbsoluteTime_SummaryProvider(valobj, dict):
291*061da546Spatrick    logger = lldb.formatters.Logger.Logger()
292*061da546Spatrick    try:
293*061da546Spatrick        value_double = struct.unpack(
294*061da546Spatrick            'd', struct.pack(
295*061da546Spatrick                'Q', valobj.GetData().uint64[0]))[0]
296*061da546Spatrick        return xcode_format_count(osx_to_python_time(value_double))
297*061da546Spatrick    except:
298*061da546Spatrick        return 'Summary Unavailable'
299*061da546Spatrick
300*061da546Spatrick
301*061da546Spatrickdef __lldb_init_module(debugger, dict):
302*061da546Spatrick    debugger.HandleCommand(
303*061da546Spatrick        "type summary add -F NSDate.NSDate_SummaryProvider NSDate")
304*061da546Spatrick    debugger.HandleCommand(
305*061da546Spatrick        "type summary add -F NSDate.CFAbsoluteTime_SummaryProvider CFAbsoluteTime")
306*061da546Spatrick    debugger.HandleCommand(
307*061da546Spatrick        "type summary add -F NSDate.NSTimeZone_SummaryProvider NSTimeZone CFTimeZoneRef")
308