1 """ 2 LLDB AppKit formatters 3 4 part of The LLVM Compiler Infrastructure 5 This file is distributed under the University of Illinois Open Source 6 License. See LICENSE.TXT for details. 7 """ 8 # example summary provider for CFBinaryHeap 9 # the real summary is now C++ code built into LLDB 10 import lldb 11 import ctypes 12 import lldb.runtime.objc.objc_runtime 13 import lldb.formatters.metrics 14 import lldb.formatters.Logger 15 16 statistics = lldb.formatters.metrics.Metrics() 17 statistics.add_metric('invalid_isa') 18 statistics.add_metric('invalid_pointer') 19 statistics.add_metric('unknown_class') 20 statistics.add_metric('code_notrun') 21 22 # despite the similary to synthetic children providers, these classes are not 23 # trying to provide anything but the length for an CFBinaryHeap, so they need not 24 # obey the interface specification for synthetic children providers 25 class CFBinaryHeapRef_SummaryProvider: 26 def adjust_for_architecture(self): 27 pass 28 29 def __init__(self, valobj, params): 30 logger = lldb.formatters.Logger.Logger() 31 self.valobj = valobj; 32 self.sys_params = params 33 if not(self.sys_params.types_cache.NSUInteger): 34 if self.sys_params.is_64_bit: 35 self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) 36 else: 37 self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) 38 self.update(); 39 40 def update(self): 41 logger = lldb.formatters.Logger.Logger() 42 self.adjust_for_architecture(); 43 44 # 8 bytes on i386 45 # 16 bytes on x64 46 # most probably 2 pointers 47 def offset(self): 48 logger = lldb.formatters.Logger.Logger() 49 return 2 * self.sys_params.pointer_size 50 51 def length(self): 52 logger = lldb.formatters.Logger.Logger() 53 size = self.valobj.CreateChildAtOffset("count", 54 self.offset(), 55 self.sys_params.types_cache.NSUInteger) 56 return size.GetValueAsUnsigned(0) 57 58 59 class CFBinaryHeapUnknown_SummaryProvider: 60 def adjust_for_architecture(self): 61 pass 62 63 def __init__(self, valobj, params): 64 logger = lldb.formatters.Logger.Logger() 65 self.valobj = valobj; 66 self.sys_params = params 67 self.update(); 68 69 def update(self): 70 logger = lldb.formatters.Logger.Logger() 71 self.adjust_for_architecture(); 72 73 def length(self): 74 logger = lldb.formatters.Logger.Logger() 75 stream = lldb.SBStream() 76 self.valobj.GetExpressionPath(stream) 77 num_children_vo = self.valobj.CreateValueFromExpression("count","(int)CFBinaryHeapGetCount(" + stream.GetData() + " )"); 78 if num_children_vo.IsValid(): 79 return num_children_vo.GetValueAsUnsigned(0) 80 return '<variable is not CFBinaryHeap>' 81 82 83 def GetSummary_Impl(valobj): 84 logger = lldb.formatters.Logger.Logger() 85 global statistics 86 class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) 87 if wrapper: 88 return wrapper 89 90 name_string = class_data.class_name() 91 actual_name = class_data.class_name() 92 93 logger >> "name string got was " + str(name_string) + " but actual name is " + str(actual_name) 94 95 if class_data.is_cftype(): 96 # CFBinaryHeap does not expose an actual NSWrapper type, so we have to check that this is 97 # an NSCFType and then check we are a pointer-to CFBinaryHeap 98 valobj_type = valobj.GetType() 99 if valobj_type.IsValid() and valobj_type.IsPointerType(): 100 valobj_type = valobj_type.GetPointeeType() 101 if valobj_type.IsValid(): 102 actual_name = valobj_type.GetName() 103 if actual_name == '__CFBinaryHeap': 104 wrapper = CFBinaryHeapRef_SummaryProvider(valobj, class_data.sys_params) 105 statistics.metric_hit('code_notrun',valobj) 106 return wrapper 107 wrapper = CFBinaryHeapUnknown_SummaryProvider(valobj, class_data.sys_params) 108 statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string) 109 return wrapper; 110 111 def CFBinaryHeap_SummaryProvider (valobj,dict): 112 logger = lldb.formatters.Logger.Logger() 113 provider = GetSummary_Impl(valobj); 114 if provider != None: 115 if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description): 116 return provider.message() 117 try: 118 summary = provider.length(); 119 except: 120 summary = None 121 logger >> "summary got from provider: " + str(summary) 122 # for some reason, one needs to clear some bits for the count 123 # to be correct when using CF(Mutable)BagRef on x64 124 # the bit mask was derived through experimentation 125 # (if counts start looking weird, then most probably 126 # the mask needs to be changed) 127 if summary == None: 128 summary = '<variable is not CFBinaryHeap>' 129 elif isinstance(summary,basestring): 130 pass 131 else: 132 if provider.sys_params.is_64_bit: 133 summary = summary & ~0x1fff000000000000 134 if summary == 1: 135 return '@"1 item"' 136 else: 137 summary = '@"' + str(summary) + ' items"' 138 return summary 139 return 'Summary Unavailable' 140 141 def __lldb_init_module(debugger,dict): 142 debugger.HandleCommand("type summary add -F CFBinaryHeap.CFBinaryHeap_SummaryProvider CFBinaryHeapRef") 143