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