1# summary provider for CF(Mutable)BitVector 2import lldb 3import ctypes 4import objc_runtime 5import metrics 6 7# first define some utility functions 8def byte_index(abs_pos): 9 return abs_pos/8 10 11def bit_index(abs_pos): 12 return abs_pos & 7 13 14def get_bit(byte,index): 15 if index < 0 or index > 7: 16 return None 17 return (byte >> (7-index)) & 1 18 19def grab_array_item_data(pointer,index): 20 return pointer.GetPointeeData(index,1) 21 22statistics = metrics.Metrics() 23statistics.add_metric('invalid_isa') 24statistics.add_metric('invalid_pointer') 25statistics.add_metric('unknown_class') 26statistics.add_metric('code_notrun') 27 28# despite the similary to synthetic children providers, these classes are not 29# trying to provide anything but a summary for a CF*BitVector, so they need not 30# obey the interface specification for synthetic children providers 31class CFBitVectorKnown_SummaryProvider: 32 def adjust_for_architecture(self): 33 self.uiint_size = self.sys_params.types_cache.NSUInteger.GetByteSize() 34 pass 35 36 def __init__(self, valobj, params): 37 self.valobj = valobj; 38 self.sys_params = params 39 if not(self.sys_params.types_cache.NSUInteger): 40 if self.sys_params.is_64_bit: 41 self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) 42 else: 43 self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) 44 if not(self.sys_params.types_cache.charptr): 45 self.sys_params.types_cache.charptr = self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar).GetPointerType() 46 self.update(); 47 48 def update(self): 49 self.adjust_for_architecture(); 50 51 # we skip the CFRuntimeBase 52 # then the next CFIndex is the count 53 # then we skip another CFIndex and then we get at a byte array 54 # that wraps the individual bits 55 56 def contents(self): 57 count_vo = self.valobj.CreateChildAtOffset("count",self.sys_params.cfruntime_size, 58 self.sys_params.types_cache.NSUInteger) 59 count = count_vo.GetValueAsUnsigned(0) 60 if count == 0: 61 return '(empty)' 62 63 array_vo = self.valobj.CreateChildAtOffset("data", 64 self.sys_params.cfruntime_size+2*self.uiint_size, 65 self.sys_params.types_cache.charptr) 66 67 data_list = [] 68 cur_byte_pos = None 69 for i in range(0,count): 70 if cur_byte_pos == None: 71 cur_byte_pos = byte_index(i) 72 cur_byte = grab_array_item_data(array_vo,cur_byte_pos) 73 cur_byte_val = cur_byte.uint8[0] 74 else: 75 byte_pos = byte_index(i) 76 # do not fetch the pointee data every single time through 77 if byte_pos != cur_byte_pos: 78 cur_byte_pos = byte_pos 79 cur_byte = grab_array_item_data(array_vo,cur_byte_pos) 80 cur_byte_val = cur_byte.uint8[0] 81 bit = get_bit(cur_byte_val,bit_index(i)) 82 if (i % 4) == 0: 83 data_list.append(' ') 84 if bit == 1: 85 data_list.append('1') 86 else: 87 data_list.append('0') 88 return ''.join(data_list) 89 90 91class CFBitVectorUnknown_SummaryProvider: 92 def adjust_for_architecture(self): 93 pass 94 95 def __init__(self, valobj, params): 96 self.valobj = valobj; 97 self.sys_params = params 98 self.update(); 99 100 def update(self): 101 self.adjust_for_architecture(); 102 103 def contents(self): 104 return '*** unknown class *** very bad thing *** find out my name ***' 105 106 107def GetSummary_Impl(valobj): 108 global statistics 109 class_data = objc_runtime.ObjCRuntime(valobj) 110 if class_data.is_valid() == False: 111 statistics.metric_hit('invalid_pointer',valobj) 112 wrapper = None 113 return 114 class_data = class_data.read_class_data() 115 if class_data.is_valid() == False: 116 statistics.metric_hit('invalid_isa',valobj) 117 wrapper = None 118 return 119 if class_data.is_kvo(): 120 class_data = class_data.get_superclass() 121 if class_data.is_valid() == False: 122 statistics.metric_hit('invalid_isa',valobj) 123 wrapper = None 124 return 125 126 name_string = class_data.class_name() 127 if name_string == '__NSCFType': 128 # CFBitVectorRef does not expose an actual NSWrapper type, so we have to check that this is 129 # an NSCFType and then check we are a pointer-to CFBitVectorRef 130 valobj_type = valobj.GetType() 131 if valobj_type.IsValid() and valobj_type.IsPointerType(): 132 pointee_type = valobj_type.GetPointeeType() 133 if pointee_type.GetName() == '__CFBitVector' or pointee_type.GetName() == '__CFMutableBitVector': 134 wrapper = CFBitVectorKnown_SummaryProvider(valobj, class_data.sys_params) 135 statistics.metric_hit('code_notrun',valobj) 136 else: 137 wrapper = CFBitVectorUnknown_SummaryProvider(valobj) 138 print pointee_type.GetName() 139 else: 140 wrapper = CFBitVectorUnknown_SummaryProvider(valobj, class_data.sys_params) 141 print name_string 142 statistics.metric_hit('unknown_class',str(valobj) + " seen as " + name_string) 143 return wrapper; 144 145def CFBitVector_SummaryProvider (valobj,dict): 146 provider = GetSummary_Impl(valobj); 147 if provider != None: 148 #try: 149 summary = provider.contents(); 150 #except: 151 # summary = None 152 if summary == None or summary == '': 153 summary = 'no valid bitvector here' 154 return summary 155 return '' 156 157def __lldb_init_module(debugger,dict): 158 debugger.HandleCommand("type summary add -F CFBitVector.CFBitVector_SummaryProvider CFBitVectorRef CFMutableBitVectorRef") 159