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 NS(Mutable)IndexSet 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 count of values for an NSIndexSet, so they need not 24 # obey the interface specification for synthetic children providers 25 class NSIndexSetClass_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 self.sys_params.types_cache.uint32 = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) 37 else: 38 self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) 39 self.sys_params.types_cache.uint32 = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) 40 if not(self.sys_params.types_cache.uint32): 41 self.sys_params.types_cache.uint32 = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt) 42 self.update(); 43 44 def update(self): 45 logger = lldb.formatters.Logger.Logger() 46 self.adjust_for_architecture(); 47 48 # NS(Mutable)IndexSet works in one of two modes: when having a compact block of data (e.g. a Range) 49 # the count is stored in the set itself, 3 pointers into it 50 # otherwise, it will store a pointer to an additional data structure (2 pointers into itself) and this 51 # additional structure will contain the count two pointers deep 52 # a bunch of flags allow us to detect an empty set, vs. a one-range set, vs. a multi-range set 53 def count(self): 54 logger = lldb.formatters.Logger.Logger() 55 mode_chooser_vo = self.valobj.CreateChildAtOffset("mode_chooser", 56 self.sys_params.pointer_size, 57 self.sys_params.types_cache.uint32) 58 mode_chooser = mode_chooser_vo.GetValueAsUnsigned(0) 59 if self.sys_params.is_64_bit: 60 mode_chooser = mode_chooser & 0x00000000FFFFFFFF 61 # empty set 62 if mode_chooser & 0x01 == 1: 63 return 0 64 # single range 65 if mode_chooser & 0x02 == 2: 66 mode = 1 67 # multi range 68 else: 69 mode = 2 70 if mode == 1: 71 count_vo = self.valobj.CreateChildAtOffset("count", 72 3*self.sys_params.pointer_size, 73 self.sys_params.types_cache.NSUInteger) 74 else: 75 count_ptr = self.valobj.CreateChildAtOffset("count_ptr", 76 2*self.sys_params.pointer_size, 77 self.sys_params.types_cache.NSUInteger) 78 count_vo = self.valobj.CreateValueFromAddress("count", 79 count_ptr.GetValueAsUnsigned()+2*self.sys_params.pointer_size, 80 self.sys_params.types_cache.NSUInteger) 81 return count_vo.GetValueAsUnsigned(0) 82 83 84 class NSIndexSetUnknown_SummaryProvider: 85 def adjust_for_architecture(self): 86 pass 87 88 def __init__(self, valobj, params): 89 logger = lldb.formatters.Logger.Logger() 90 self.valobj = valobj; 91 self.sys_params = params 92 self.update(); 93 94 def update(self): 95 logger = lldb.formatters.Logger.Logger() 96 self.adjust_for_architecture(); 97 98 def count(self): 99 logger = lldb.formatters.Logger.Logger() 100 stream = lldb.SBStream() 101 self.valobj.GetExpressionPath(stream) 102 expr = "(int)[" + stream.GetData() + " count]" 103 num_children_vo = self.valobj.CreateValueFromExpression("count",expr) 104 if num_children_vo.IsValid(): 105 return num_children_vo.GetValueAsUnsigned(0) 106 return '<variable is not NSIndexSet>' 107 108 109 def GetSummary_Impl(valobj): 110 logger = lldb.formatters.Logger.Logger() 111 global statistics 112 class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) 113 if wrapper: 114 return wrapper 115 116 name_string = class_data.class_name() 117 logger >> "class name is: " + str(name_string) 118 119 if name_string == 'NSIndexSet' or name_string == 'NSMutableIndexSet': 120 wrapper = NSIndexSetClass_SummaryProvider(valobj, class_data.sys_params) 121 statistics.metric_hit('code_notrun',valobj) 122 else: 123 wrapper = NSIndexSetUnknown_SummaryProvider(valobj, class_data.sys_params) 124 statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string) 125 return wrapper; 126 127 128 def NSIndexSet_SummaryProvider (valobj,dict): 129 logger = lldb.formatters.Logger.Logger() 130 provider = GetSummary_Impl(valobj); 131 if provider != None: 132 if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description): 133 return provider.message() 134 try: 135 summary = provider.count(); 136 except: 137 summary = None 138 logger >> "got summary " + str(summary) 139 if summary == None: 140 summary = '<variable is not NSIndexSet>' 141 if isinstance(summary, basestring): 142 return summary 143 else: 144 summary = str(summary) + (' indexes' if summary != 1 else ' index') 145 return summary 146 return 'Summary Unavailable' 147 148 149 def __lldb_init_module(debugger,dict): 150 debugger.HandleCommand("type summary add -F NSIndexSet.NSIndexSet_SummaryProvider NSIndexSet NSMutableIndexSet") 151