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