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