1*061da546Spatrick""" 2*061da546SpatrickLLDB AppKit formatters 3*061da546Spatrick 4*061da546SpatrickPart of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5*061da546SpatrickSee https://llvm.org/LICENSE.txt for license information. 6*061da546SpatrickSPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7*061da546Spatrick""" 8*061da546Spatrick 9*061da546Spatrick# summary provider for CF(Mutable)BitVector 10*061da546Spatrickimport lldb 11*061da546Spatrickimport ctypes 12*061da546Spatrickimport lldb.runtime.objc.objc_runtime 13*061da546Spatrickimport lldb.formatters.metrics 14*061da546Spatrickimport lldb.formatters.Logger 15*061da546Spatrick 16*061da546Spatrick# first define some utility functions 17*061da546Spatrick 18*061da546Spatrick 19*061da546Spatrickdef byte_index(abs_pos): 20*061da546Spatrick logger = lldb.formatters.Logger.Logger() 21*061da546Spatrick return abs_pos / 8 22*061da546Spatrick 23*061da546Spatrick 24*061da546Spatrickdef bit_index(abs_pos): 25*061da546Spatrick logger = lldb.formatters.Logger.Logger() 26*061da546Spatrick return abs_pos & 7 27*061da546Spatrick 28*061da546Spatrick 29*061da546Spatrickdef get_bit(byte, index): 30*061da546Spatrick logger = lldb.formatters.Logger.Logger() 31*061da546Spatrick if index < 0 or index > 7: 32*061da546Spatrick return None 33*061da546Spatrick return (byte >> (7 - index)) & 1 34*061da546Spatrick 35*061da546Spatrick 36*061da546Spatrickdef grab_array_item_data(pointer, index): 37*061da546Spatrick logger = lldb.formatters.Logger.Logger() 38*061da546Spatrick return pointer.GetPointeeData(index, 1) 39*061da546Spatrick 40*061da546Spatrickstatistics = lldb.formatters.metrics.Metrics() 41*061da546Spatrickstatistics.add_metric('invalid_isa') 42*061da546Spatrickstatistics.add_metric('invalid_pointer') 43*061da546Spatrickstatistics.add_metric('unknown_class') 44*061da546Spatrickstatistics.add_metric('code_notrun') 45*061da546Spatrick 46*061da546Spatrick# despite the similary to synthetic children providers, these classes are not 47*061da546Spatrick# trying to provide anything but a summary for a CF*BitVector, so they need not 48*061da546Spatrick# obey the interface specification for synthetic children providers 49*061da546Spatrick 50*061da546Spatrick 51*061da546Spatrickclass CFBitVectorKnown_SummaryProvider: 52*061da546Spatrick 53*061da546Spatrick def adjust_for_architecture(self): 54*061da546Spatrick logger = lldb.formatters.Logger.Logger() 55*061da546Spatrick self.uiint_size = self.sys_params.types_cache.NSUInteger.GetByteSize() 56*061da546Spatrick pass 57*061da546Spatrick 58*061da546Spatrick def __init__(self, valobj, params): 59*061da546Spatrick logger = lldb.formatters.Logger.Logger() 60*061da546Spatrick self.valobj = valobj 61*061da546Spatrick self.sys_params = params 62*061da546Spatrick if not(self.sys_params.types_cache.NSUInteger): 63*061da546Spatrick if self.sys_params.is_64_bit: 64*061da546Spatrick self.sys_params.types_cache.NSUInteger = self.valobj.GetType( 65*061da546Spatrick ).GetBasicType(lldb.eBasicTypeUnsignedLong) 66*061da546Spatrick else: 67*061da546Spatrick self.sys_params.types_cache.NSUInteger = self.valobj.GetType( 68*061da546Spatrick ).GetBasicType(lldb.eBasicTypeUnsignedInt) 69*061da546Spatrick if not(self.sys_params.types_cache.charptr): 70*061da546Spatrick self.sys_params.types_cache.charptr = self.valobj.GetType( 71*061da546Spatrick ).GetBasicType(lldb.eBasicTypeChar).GetPointerType() 72*061da546Spatrick self.update() 73*061da546Spatrick 74*061da546Spatrick def update(self): 75*061da546Spatrick logger = lldb.formatters.Logger.Logger() 76*061da546Spatrick self.adjust_for_architecture() 77*061da546Spatrick 78*061da546Spatrick # we skip the CFRuntimeBase 79*061da546Spatrick # then the next CFIndex is the count 80*061da546Spatrick # then we skip another CFIndex and then we get at a byte array 81*061da546Spatrick # that wraps the individual bits 82*061da546Spatrick 83*061da546Spatrick def contents(self): 84*061da546Spatrick logger = lldb.formatters.Logger.Logger() 85*061da546Spatrick count_vo = self.valobj.CreateChildAtOffset( 86*061da546Spatrick "count", 87*061da546Spatrick self.sys_params.cfruntime_size, 88*061da546Spatrick self.sys_params.types_cache.NSUInteger) 89*061da546Spatrick count = count_vo.GetValueAsUnsigned(0) 90*061da546Spatrick if count == 0: 91*061da546Spatrick return '(empty)' 92*061da546Spatrick 93*061da546Spatrick array_vo = self.valobj.CreateChildAtOffset( 94*061da546Spatrick "data", 95*061da546Spatrick self.sys_params.cfruntime_size + 96*061da546Spatrick 2 * 97*061da546Spatrick self.uiint_size, 98*061da546Spatrick self.sys_params.types_cache.charptr) 99*061da546Spatrick 100*061da546Spatrick data_list = [] 101*061da546Spatrick cur_byte_pos = None 102*061da546Spatrick for i in range(0, count): 103*061da546Spatrick if cur_byte_pos is None: 104*061da546Spatrick cur_byte_pos = byte_index(i) 105*061da546Spatrick cur_byte = grab_array_item_data(array_vo, cur_byte_pos) 106*061da546Spatrick cur_byte_val = cur_byte.uint8[0] 107*061da546Spatrick else: 108*061da546Spatrick byte_pos = byte_index(i) 109*061da546Spatrick # do not fetch the pointee data every single time through 110*061da546Spatrick if byte_pos != cur_byte_pos: 111*061da546Spatrick cur_byte_pos = byte_pos 112*061da546Spatrick cur_byte = grab_array_item_data(array_vo, cur_byte_pos) 113*061da546Spatrick cur_byte_val = cur_byte.uint8[0] 114*061da546Spatrick bit = get_bit(cur_byte_val, bit_index(i)) 115*061da546Spatrick if (i % 4) == 0: 116*061da546Spatrick data_list.append(' ') 117*061da546Spatrick if bit == 1: 118*061da546Spatrick data_list.append('1') 119*061da546Spatrick else: 120*061da546Spatrick data_list.append('0') 121*061da546Spatrick return ''.join(data_list) 122*061da546Spatrick 123*061da546Spatrick 124*061da546Spatrickclass CFBitVectorUnknown_SummaryProvider: 125*061da546Spatrick 126*061da546Spatrick def adjust_for_architecture(self): 127*061da546Spatrick pass 128*061da546Spatrick 129*061da546Spatrick def __init__(self, valobj, params): 130*061da546Spatrick logger = lldb.formatters.Logger.Logger() 131*061da546Spatrick self.valobj = valobj 132*061da546Spatrick self.sys_params = params 133*061da546Spatrick self.update() 134*061da546Spatrick 135*061da546Spatrick def update(self): 136*061da546Spatrick logger = lldb.formatters.Logger.Logger() 137*061da546Spatrick self.adjust_for_architecture() 138*061da546Spatrick 139*061da546Spatrick def contents(self): 140*061da546Spatrick logger = lldb.formatters.Logger.Logger() 141*061da546Spatrick return '<unable to summarize this CFBitVector>' 142*061da546Spatrick 143*061da546Spatrick 144*061da546Spatrickdef GetSummary_Impl(valobj): 145*061da546Spatrick logger = lldb.formatters.Logger.Logger() 146*061da546Spatrick global statistics 147*061da546Spatrick class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( 148*061da546Spatrick valobj, statistics) 149*061da546Spatrick if wrapper: 150*061da546Spatrick return wrapper 151*061da546Spatrick 152*061da546Spatrick name_string = class_data.class_name() 153*061da546Spatrick actual_name = name_string 154*061da546Spatrick 155*061da546Spatrick logger >> "name string got was " + \ 156*061da546Spatrick str(name_string) + " but actual name is " + str(actual_name) 157*061da546Spatrick 158*061da546Spatrick if class_data.is_cftype(): 159*061da546Spatrick # CFBitVectorRef does not expose an actual NSWrapper type, so we have to check that this is 160*061da546Spatrick # an NSCFType and then check we are a pointer-to CFBitVectorRef 161*061da546Spatrick valobj_type = valobj.GetType() 162*061da546Spatrick if valobj_type.IsValid() and valobj_type.IsPointerType(): 163*061da546Spatrick valobj_type = valobj_type.GetPointeeType() 164*061da546Spatrick if valobj_type.IsValid(): 165*061da546Spatrick actual_name = valobj_type.GetName() 166*061da546Spatrick if actual_name == '__CFBitVector' or actual_name == '__CFMutableBitVector': 167*061da546Spatrick wrapper = CFBitVectorKnown_SummaryProvider( 168*061da546Spatrick valobj, class_data.sys_params) 169*061da546Spatrick statistics.metric_hit('code_notrun', valobj) 170*061da546Spatrick else: 171*061da546Spatrick wrapper = CFBitVectorUnknown_SummaryProvider( 172*061da546Spatrick valobj, class_data.sys_params) 173*061da546Spatrick print(actual_name) 174*061da546Spatrick else: 175*061da546Spatrick wrapper = CFBitVectorUnknown_SummaryProvider( 176*061da546Spatrick valobj, class_data.sys_params) 177*061da546Spatrick print(name_string) 178*061da546Spatrick statistics.metric_hit( 179*061da546Spatrick 'unknown_class', 180*061da546Spatrick valobj.GetName() + 181*061da546Spatrick " seen as " + 182*061da546Spatrick name_string) 183*061da546Spatrick return wrapper 184*061da546Spatrick 185*061da546Spatrick 186*061da546Spatrickdef CFBitVector_SummaryProvider(valobj, dict): 187*061da546Spatrick logger = lldb.formatters.Logger.Logger() 188*061da546Spatrick provider = GetSummary_Impl(valobj) 189*061da546Spatrick if provider is not None: 190*061da546Spatrick if isinstance( 191*061da546Spatrick provider, 192*061da546Spatrick lldb.runtime.objc.objc_runtime.SpecialSituation_Description): 193*061da546Spatrick return provider.message() 194*061da546Spatrick try: 195*061da546Spatrick summary = provider.contents() 196*061da546Spatrick except: 197*061da546Spatrick summary = None 198*061da546Spatrick logger >> "summary got from provider: " + str(summary) 199*061da546Spatrick if summary is None or summary == '': 200*061da546Spatrick summary = '<variable is not CFBitVector>' 201*061da546Spatrick return summary 202*061da546Spatrick return 'Summary Unavailable' 203*061da546Spatrick 204*061da546Spatrick 205*061da546Spatrickdef __lldb_init_module(debugger, dict): 206*061da546Spatrick debugger.HandleCommand( 207*061da546Spatrick "type summary add -F CFBitVector.CFBitVector_SummaryProvider CFBitVectorRef CFMutableBitVectorRef") 208