Home | History | Annotate | Download | only in cocoa
      1 """
      2 LLDB AppKit formatters
      3 
      4 part of The LLVM Compiler Infrastructure
      5 This file is distributed under the University of Illinois Open Source
      6 License. See LICENSE.TXT for details.
      7 """
      8 # example summary provider for NSArray
      9 # the real summary is now C++ code built into LLDB
     10 import lldb
     11 import ctypes
     12 import lldb.runtime.objc.objc_runtime
     13 import lldb.formatters.metrics
     14 import lldb.formatters.Logger
     15 
     16 statistics = lldb.formatters.metrics.Metrics()
     17 statistics.add_metric('invalid_isa')
     18 statistics.add_metric('invalid_pointer')
     19 statistics.add_metric('unknown_class')
     20 statistics.add_metric('code_notrun')
     21 
     22 # much less functional than the other two cases below
     23 # just runs code to get to the count and then returns
     24 # no children
     25 class NSArrayKVC_SynthProvider:
     26 
     27 	def adjust_for_architecture(self):
     28 		pass
     29 
     30 	def __init__(self, valobj, dict, params):
     31 		logger = lldb.formatters.Logger.Logger()
     32 		self.valobj = valobj;
     33 		self.update()
     34 
     35 	def update(self):
     36 		logger = lldb.formatters.Logger.Logger()
     37 		self.adjust_for_architecture();
     38 
     39 	def num_children(self):
     40 		logger = lldb.formatters.Logger.Logger()
     41 		stream = lldb.SBStream()
     42 		self.valobj.GetExpressionPath(stream)
     43 		num_children_vo = self.valobj.CreateValueFromExpression("count","(int)[" + stream.GetData() + " count]");
     44 		if num_children_vo.IsValid():
     45 			return num_children_vo.GetValueAsUnsigned(0)
     46 		return "<variable is not NSArray>"
     47 
     48 # much less functional than the other two cases below
     49 # just runs code to get to the count and then returns
     50 # no children
     51 class NSArrayCF_SynthProvider:
     52 
     53 	def adjust_for_architecture(self):
     54 		pass
     55 
     56 	def __init__(self, valobj, dict, params):
     57 		logger = lldb.formatters.Logger.Logger()
     58 		self.valobj = valobj;
     59 		self.sys_params = params
     60 		if not (self.sys_params.types_cache.ulong):
     61 			self.sys_params.types_cache.ulong = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
     62 		self.update()
     63 
     64 	def update(self):
     65 		logger = lldb.formatters.Logger.Logger()
     66 		self.adjust_for_architecture();
     67 
     68 	def num_children(self):
     69 		logger = lldb.formatters.Logger.Logger()
     70 		num_children_vo = self.valobj.CreateChildAtOffset("count",
     71 							self.sys_params.cfruntime_size,
     72 							self.sys_params.types_cache.ulong)
     73 		return num_children_vo.GetValueAsUnsigned(0)
     74 
     75 class NSArrayI_SynthProvider:
     76 	def adjust_for_architecture(self):
     77 		pass
     78 
     79 	def __init__(self, valobj, dict, params):
     80 		logger = lldb.formatters.Logger.Logger()
     81 		self.valobj = valobj;
     82 		self.sys_params = params
     83 		if not(self.sys_params.types_cache.long):
     84 			self.sys_params.types_cache.long = self.valobj.GetType().GetBasicType(lldb.eBasicTypeLong)
     85 		self.update()
     86 
     87 	def update(self):
     88 		logger = lldb.formatters.Logger.Logger()
     89 		self.adjust_for_architecture();
     90 
     91 	# skip the isa pointer and get at the size
     92 	def num_children(self):
     93 		logger = lldb.formatters.Logger.Logger()
     94 		count = self.valobj.CreateChildAtOffset("count",
     95 				self.sys_params.pointer_size,
     96 				self.sys_params.types_cache.long);
     97 		return count.GetValueAsUnsigned(0)
     98 
     99 class NSArrayM_SynthProvider:
    100 	def adjust_for_architecture(self):
    101 		pass
    102 
    103 	def __init__(self, valobj, dict, params):
    104 		logger = lldb.formatters.Logger.Logger()
    105 		self.valobj = valobj;
    106 		self.sys_params = params
    107 		if not(self.sys_params.types_cache.long):
    108 			self.sys_params.types_cache.long = self.valobj.GetType().GetBasicType(lldb.eBasicTypeLong)
    109 		self.update()
    110 
    111 	def update(self):
    112 		logger = lldb.formatters.Logger.Logger()
    113 		self.adjust_for_architecture();
    114 
    115 	# skip the isa pointer and get at the size
    116 	def num_children(self):
    117 		logger = lldb.formatters.Logger.Logger()
    118 		count = self.valobj.CreateChildAtOffset("count",
    119 				self.sys_params.pointer_size,
    120 				self.sys_params.types_cache.long);
    121 		return count.GetValueAsUnsigned(0)
    122 
    123 # this is the actual synth provider, but is just a wrapper that checks
    124 # whether valobj is an instance of __NSArrayI or __NSArrayM and sets up an
    125 # appropriate backend layer to do the computations 
    126 class NSArray_SynthProvider:
    127 	def adjust_for_architecture(self):
    128 		pass
    129 
    130 	def __init__(self, valobj, dict):
    131 		logger = lldb.formatters.Logger.Logger()
    132 		self.valobj = valobj;
    133 		self.adjust_for_architecture()
    134 		self.error = False
    135 		self.wrapper = self.make_wrapper()
    136 		self.invalid = (self.wrapper == None)
    137 
    138 	def num_children(self):
    139 		logger = lldb.formatters.Logger.Logger()
    140 		if self.wrapper == None:
    141 			return 0;
    142 		return self.wrapper.num_children()
    143 
    144 	def update(self):
    145 		logger = lldb.formatters.Logger.Logger()
    146 		if self.wrapper == None:
    147 			return
    148 		self.wrapper.update()
    149 
    150 	# this code acts as our defense against NULL and unitialized
    151 	# NSArray pointers, which makes it much longer than it would be otherwise
    152 	def make_wrapper(self):
    153 		logger = lldb.formatters.Logger.Logger()
    154 		if self.valobj.GetValueAsUnsigned() == 0:
    155 			self.error = True
    156 			return lldb.runtime.objc.objc_runtime.InvalidPointer_Description(True)
    157 		else:
    158 			global statistics
    159 			class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(self.valobj,statistics)
    160 			if wrapper:
    161 				self.error = True
    162 				return wrapper
    163 		
    164 		name_string = class_data.class_name()
    165 		
    166 		logger >> "Class name is " + str(name_string)
    167 		
    168 		if name_string == '__NSArrayI':
    169 			wrapper = NSArrayI_SynthProvider(self.valobj, dict, class_data.sys_params)
    170 			statistics.metric_hit('code_notrun',self.valobj.GetName())
    171 		elif name_string == '__NSArrayM':
    172 			wrapper = NSArrayM_SynthProvider(self.valobj, dict, class_data.sys_params)
    173 			statistics.metric_hit('code_notrun',self.valobj.GetName())
    174 		elif name_string == '__NSCFArray':
    175 			wrapper = NSArrayCF_SynthProvider(self.valobj, dict, class_data.sys_params)
    176 			statistics.metric_hit('code_notrun',self.valobj.GetName())
    177 		else:
    178 			wrapper = NSArrayKVC_SynthProvider(self.valobj, dict, class_data.sys_params)
    179 			statistics.metric_hit('unknown_class',str(self.valobj.GetName()) + " seen as " + name_string)
    180 		return wrapper;
    181 
    182 def CFArray_SummaryProvider (valobj,dict):
    183 	logger = lldb.formatters.Logger.Logger()
    184 	provider = NSArray_SynthProvider(valobj,dict);
    185 	if provider.invalid == False:
    186 		if provider.error == True:
    187 			return provider.wrapper.message()
    188 		try:
    189 			summary = int(provider.num_children());
    190 		except:
    191 			summary = None
    192 		logger >> "provider gave me " + str(summary)
    193 		if summary == None:
    194 			summary = '<variable is not NSArray>'
    195 		elif isinstance(summary,basestring):
    196 			pass
    197 		else:
    198 			# we format it like it were a CFString to make it look the same as the summary from Xcode
    199 			summary = '@"' + str(summary) + (" objects" if summary != 1 else " object") + '"'
    200 		return summary
    201 	return 'Summary Unavailable'
    202 
    203 def __lldb_init_module(debugger,dict):
    204 	debugger.HandleCommand("type summary add -F CFArray.CFArray_SummaryProvider NSArray CFArrayRef CFMutableArrayRef")
    205