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