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