| """ | 
 | LLDB AppKit formatters | 
 |  | 
 | part of The LLVM Compiler Infrastructure | 
 | This file is distributed under the University of Illinois Open Source | 
 | License. See LICENSE.TXT for details. | 
 | """ | 
 | # example summary provider for NSDate | 
 | # the real summary is now C++ code built into LLDB | 
 | import lldb | 
 | import ctypes | 
 | import lldb.runtime.objc.objc_runtime | 
 | import lldb.formatters.metrics | 
 | import struct | 
 | import time | 
 | import datetime | 
 | import CFString | 
 | import lldb.formatters.Logger | 
 |  | 
 | statistics = lldb.formatters.metrics.Metrics() | 
 | statistics.add_metric('invalid_isa') | 
 | statistics.add_metric('invalid_pointer') | 
 | statistics.add_metric('unknown_class') | 
 | statistics.add_metric('code_notrun') | 
 |  | 
 | # Python promises to start counting time at midnight on Jan 1st on the epoch year | 
 | # hence, all we need to know is the epoch year | 
 | python_epoch = time.gmtime(0).tm_year | 
 |  | 
 | osx_epoch = datetime.date(2001,1,1).timetuple() | 
 |  | 
 | def mkgmtime(t): | 
 | 	logger = lldb.formatters.Logger.Logger() | 
 | 	return time.mktime(t)-time.timezone | 
 |  | 
 | osx_epoch = mkgmtime(osx_epoch) | 
 |  | 
 | def osx_to_python_time(osx): | 
 | 	logger = lldb.formatters.Logger.Logger() | 
 | 	if python_epoch <= 2001: | 
 | 		return osx + osx_epoch | 
 | 	else: | 
 | 		return osx - osx_epoch | 
 |  | 
 | # represent a struct_time as a string in the format used by Xcode | 
 | def xcode_format_time(X): | 
 | 	logger = lldb.formatters.Logger.Logger() | 
 | 	return time.strftime('%Y-%m-%d %H:%M:%S %Z',X) | 
 |  | 
 | # represent a count-since-epoch as a string in the format used by Xcode | 
 | def xcode_format_count(X): | 
 | 	logger = lldb.formatters.Logger.Logger() | 
 | 	return xcode_format_time(time.localtime(X)) | 
 |  | 
 | # despite the similary to synthetic children providers, these classes are not | 
 | # trying to provide anything but the summary for NSDate, so they need not | 
 | # obey the interface specification for synthetic children providers | 
 | class NSTaggedDate_SummaryProvider: | 
 | 	def adjust_for_architecture(self): | 
 | 		pass | 
 |  | 
 | 	def __init__(self, valobj, info_bits, data, params): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		self.valobj = valobj; | 
 | 		self.sys_params = params | 
 | 		self.update(); | 
 | 		# NSDate is not using its info_bits for info like NSNumber is | 
 | 		# so we need to regroup info_bits and data | 
 | 		self.data = ((data << 8) | (info_bits << 4)) | 
 |  | 
 | 	def update(self): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		self.adjust_for_architecture(); | 
 |  | 
 | 	def value(self): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		# the value of the date-time object is wrapped into the pointer value | 
 | 		# unfortunately, it is made as a time-delta after Jan 1 2001 midnight GMT | 
 | 		# while all Python knows about is the "epoch", which is a platform-dependent | 
 | 		# year (1970 of *nix) whose Jan 1 at midnight is taken as reference | 
 | 		value_double = struct.unpack('d', struct.pack('Q', self.data))[0] | 
 | 		if value_double == -63114076800.0: | 
 | 			return '0001-12-30 00:00:00 +0000' | 
 | 		return xcode_format_count(osx_to_python_time(value_double)) | 
 |  | 
 |  | 
 | class NSUntaggedDate_SummaryProvider: | 
 | 	def adjust_for_architecture(self): | 
 | 		pass | 
 |  | 
 | 	def __init__(self, valobj, params): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		self.valobj = valobj; | 
 | 		self.sys_params = params | 
 | 		if not (self.sys_params.types_cache.double): | 
 | 			self.sys_params.types_cache.double = self.valobj.GetType().GetBasicType(lldb.eBasicTypeDouble) | 
 | 		self.update() | 
 |  | 
 | 	def update(self): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		self.adjust_for_architecture(); | 
 |  | 
 | 	def offset(self): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		return self.sys_params.pointer_size | 
 |  | 
 | 	def value(self): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		value = self.valobj.CreateChildAtOffset("value", | 
 | 							self.offset(), | 
 | 							self.sys_params.types_cache.double) | 
 | 		value_double = struct.unpack('d', struct.pack('Q', value.GetData().uint64[0]))[0] | 
 | 		if value_double == -63114076800.0: | 
 | 			return '0001-12-30 00:00:00 +0000' | 
 | 		return xcode_format_count(osx_to_python_time(value_double)) | 
 |  | 
 | class NSCalendarDate_SummaryProvider: | 
 | 	def adjust_for_architecture(self): | 
 | 		pass | 
 |  | 
 | 	def __init__(self, valobj, params): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		self.valobj = valobj; | 
 | 		self.sys_params = params | 
 | 		if not (self.sys_params.types_cache.double): | 
 | 			self.sys_params.types_cache.double = self.valobj.GetType().GetBasicType(lldb.eBasicTypeDouble) | 
 | 		self.update() | 
 |  | 
 | 	def update(self): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		self.adjust_for_architecture(); | 
 |  | 
 | 	def offset(self): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		return 2*self.sys_params.pointer_size | 
 |  | 
 | 	def value(self): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		value = self.valobj.CreateChildAtOffset("value", | 
 | 							self.offset(), | 
 | 							self.sys_params.types_cache.double) | 
 | 		value_double = struct.unpack('d', struct.pack('Q', value.GetData().uint64[0]))[0] | 
 | 		return xcode_format_count(osx_to_python_time(value_double)) | 
 |  | 
 | class NSTimeZoneClass_SummaryProvider: | 
 | 	def adjust_for_architecture(self): | 
 | 		pass | 
 |  | 
 | 	def __init__(self, valobj, params): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		self.valobj = valobj; | 
 | 		self.sys_params = params | 
 | 		if not (self.sys_params.types_cache.voidptr): | 
 | 			self.sys_params.types_cache.voidptr = self.valobj.GetType().GetBasicType(lldb.eBasicTypeVoid).GetPointerType() | 
 | 		self.update() | 
 |  | 
 | 	def update(self): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		self.adjust_for_architecture(); | 
 |  | 
 | 	def offset(self): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		return self.sys_params.pointer_size | 
 |  | 
 | 	def timezone(self): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		tz_string = self.valobj.CreateChildAtOffset("tz_name", | 
 | 							self.offset(), | 
 | 							self.sys_params.types_cache.voidptr) | 
 | 		return CFString.CFString_SummaryProvider(tz_string,None) | 
 |  | 
 | class NSUnknownDate_SummaryProvider: | 
 | 	def adjust_for_architecture(self): | 
 | 		pass | 
 |  | 
 | 	def __init__(self, valobj): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		self.valobj = valobj; | 
 | 		self.update() | 
 |  | 
 | 	def update(self): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		self.adjust_for_architecture(); | 
 |  | 
 | 	def value(self): | 
 | 		logger = lldb.formatters.Logger.Logger() | 
 | 		stream = lldb.SBStream() | 
 | 		self.valobj.GetExpressionPath(stream) | 
 | 		expr = "(NSString*)[" + stream.GetData() + " description]" | 
 | 		num_children_vo = self.valobj.CreateValueFromExpression("str",expr); | 
 | 		if num_children_vo.IsValid(): | 
 | 			return num_children_vo.GetSummary() | 
 | 		return '<variable is not NSDate>' | 
 |  | 
 | def GetSummary_Impl(valobj): | 
 | 	logger = lldb.formatters.Logger.Logger() | 
 | 	global statistics | 
 | 	class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) | 
 | 	if wrapper: | 
 | 		return wrapper | 
 | 	 | 
 | 	name_string = class_data.class_name() | 
 | 	logger >> "class name is: " + str(name_string) | 
 |  | 
 | 	if name_string == 'NSDate' or name_string == '__NSDate' or name_string == '__NSTaggedDate': | 
 | 		if class_data.is_tagged(): | 
 | 			wrapper = NSTaggedDate_SummaryProvider(valobj,class_data.info_bits(),class_data.value(), class_data.sys_params) | 
 | 			statistics.metric_hit('code_notrun',valobj) | 
 | 		else: | 
 | 			wrapper = NSUntaggedDate_SummaryProvider(valobj, class_data.sys_params) | 
 | 			statistics.metric_hit('code_notrun',valobj) | 
 | 	elif name_string == 'NSCalendarDate': | 
 | 		wrapper = NSCalendarDate_SummaryProvider(valobj, class_data.sys_params) | 
 | 		statistics.metric_hit('code_notrun',valobj) | 
 | 	elif name_string == '__NSTimeZone': | 
 | 		wrapper = NSTimeZoneClass_SummaryProvider(valobj, class_data.sys_params) | 
 | 		statistics.metric_hit('code_notrun',valobj) | 
 | 	else: | 
 | 		wrapper = NSUnknownDate_SummaryProvider(valobj) | 
 | 		statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string) | 
 | 	return wrapper; | 
 |  | 
 |  | 
 | def NSDate_SummaryProvider (valobj,dict): | 
 | 	logger = lldb.formatters.Logger.Logger() | 
 | 	provider = GetSummary_Impl(valobj); | 
 | 	if provider != None: | 
 | 		if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description): | 
 | 			return provider.message() | 
 | 		try: | 
 | 			summary = provider.value(); | 
 | 		except: | 
 | 			summary = None | 
 | 		if summary == None: | 
 | 			summary = '<variable is not NSDate>' | 
 | 		return str(summary) | 
 | 	return 'Summary Unavailable' | 
 |  | 
 | def NSTimeZone_SummaryProvider (valobj,dict): | 
 | 	logger = lldb.formatters.Logger.Logger() | 
 | 	provider = GetSummary_Impl(valobj); | 
 | 	if provider != None: | 
 | 		if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description): | 
 | 			return provider.message() | 
 | 		try: | 
 | 			summary = provider.timezone(); | 
 | 		except: | 
 | 			summary = None | 
 | 		logger >> "got summary " + str(summary) | 
 | 		if summary == None: | 
 | 			summary = '<variable is not NSTimeZone>' | 
 | 		return str(summary) | 
 | 	return 'Summary Unavailable' | 
 |  | 
 |  | 
 | def CFAbsoluteTime_SummaryProvider (valobj,dict): | 
 | 	logger = lldb.formatters.Logger.Logger() | 
 | 	try: | 
 | 		value_double = struct.unpack('d', struct.pack('Q', valobj.GetData().uint64[0]))[0] | 
 | 		return xcode_format_count(osx_to_python_time(value_double)) | 
 | 	except: | 
 | 		return 'Summary Unavailable' | 
 |  | 
 |  | 
 | def __lldb_init_module(debugger,dict): | 
 | 	debugger.HandleCommand("type summary add -F NSDate.NSDate_SummaryProvider NSDate") | 
 | 	debugger.HandleCommand("type summary add -F NSDate.CFAbsoluteTime_SummaryProvider CFAbsoluteTime") | 
 | 	debugger.HandleCommand("type summary add -F NSDate.NSTimeZone_SummaryProvider NSTimeZone CFTimeZoneRef") | 
 |  |