183 lines · python
1"""2LLDB AppKit formatters3 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-exception7"""8# example summary provider for NS(Mutable)IndexSet9# the real summary is now C++ code built into LLDB10import lldb11import ctypes12import lldb.runtime.objc.objc_runtime13import lldb.formatters.metrics14import lldb.formatters.Logger15 16statistics = lldb.formatters.metrics.Metrics()17statistics.add_metric("invalid_isa")18statistics.add_metric("invalid_pointer")19statistics.add_metric("unknown_class")20statistics.add_metric("code_notrun")21 22# despite the similary to synthetic children providers, these classes are not23# trying to provide anything but the count of values for an NSIndexSet, so they need not24# obey the interface specification for synthetic children providers25 26 27class NSIndexSetClass_SummaryProvider:28 def adjust_for_architecture(self):29 pass30 31 def __init__(self, valobj, params):32 logger = lldb.formatters.Logger.Logger()33 self.valobj = valobj34 self.sys_params = params35 if not (self.sys_params.types_cache.NSUInteger):36 if self.sys_params.is_64_bit:37 self.sys_params.types_cache.NSUInteger = (38 self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)39 )40 self.sys_params.types_cache.uint32 = self.valobj.GetType().GetBasicType(41 lldb.eBasicTypeUnsignedInt42 )43 else:44 self.sys_params.types_cache.NSUInteger = (45 self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)46 )47 self.sys_params.types_cache.uint32 = self.valobj.GetType().GetBasicType(48 lldb.eBasicTypeUnsignedInt49 )50 if not (self.sys_params.types_cache.uint32):51 self.sys_params.types_cache.uint32 = self.valobj.GetType().GetBasicType(52 lldb.eBasicTypeUnsignedInt53 )54 self.update()55 56 def update(self):57 logger = lldb.formatters.Logger.Logger()58 self.adjust_for_architecture()59 60 # NS(Mutable)IndexSet works in one of two modes: when having a compact block of data (e.g. a Range)61 # the count is stored in the set itself, 3 pointers into it62 # otherwise, it will store a pointer to an additional data structure (2 pointers into itself) and this63 # additional structure will contain the count two pointers deep64 # a bunch of flags allow us to detect an empty set, vs. a one-range set,65 # vs. a multi-range set66 def count(self):67 logger = lldb.formatters.Logger.Logger()68 mode_chooser_vo = self.valobj.CreateChildAtOffset(69 "mode_chooser",70 self.sys_params.pointer_size,71 self.sys_params.types_cache.uint32,72 )73 mode_chooser = mode_chooser_vo.GetValueAsUnsigned(0)74 if self.sys_params.is_64_bit:75 mode_chooser = mode_chooser & 0x00000000FFFFFFFF76 # empty set77 if mode_chooser & 0x01 == 1:78 return 079 # single range80 if mode_chooser & 0x02 == 2:81 mode = 182 # multi range83 else:84 mode = 285 if mode == 1:86 count_vo = self.valobj.CreateChildAtOffset(87 "count",88 3 * self.sys_params.pointer_size,89 self.sys_params.types_cache.NSUInteger,90 )91 else:92 count_ptr = self.valobj.CreateChildAtOffset(93 "count_ptr",94 2 * self.sys_params.pointer_size,95 self.sys_params.types_cache.NSUInteger,96 )97 count_vo = self.valobj.CreateValueFromAddress(98 "count",99 count_ptr.GetValueAsUnsigned() + 2 * self.sys_params.pointer_size,100 self.sys_params.types_cache.NSUInteger,101 )102 return count_vo.GetValueAsUnsigned(0)103 104 105class NSIndexSetUnknown_SummaryProvider:106 def adjust_for_architecture(self):107 pass108 109 def __init__(self, valobj, params):110 logger = lldb.formatters.Logger.Logger()111 self.valobj = valobj112 self.sys_params = params113 self.update()114 115 def update(self):116 logger = lldb.formatters.Logger.Logger()117 self.adjust_for_architecture()118 119 def count(self):120 logger = lldb.formatters.Logger.Logger()121 stream = lldb.SBStream()122 self.valobj.GetExpressionPath(stream)123 expr = "(int)[" + stream.GetData() + " count]"124 num_children_vo = self.valobj.CreateValueFromExpression("count", expr)125 if num_children_vo.IsValid():126 return num_children_vo.GetValueAsUnsigned(0)127 return "<variable is not NSIndexSet>"128 129 130def GetSummary_Impl(valobj):131 logger = lldb.formatters.Logger.Logger()132 global statistics133 (134 class_data,135 wrapper,136 ) = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(137 valobj, statistics138 )139 if wrapper:140 return wrapper141 142 name_string = class_data.class_name()143 logger >> "class name is: " + str(name_string)144 145 if name_string == "NSIndexSet" or name_string == "NSMutableIndexSet":146 wrapper = NSIndexSetClass_SummaryProvider(valobj, class_data.sys_params)147 statistics.metric_hit("code_notrun", valobj)148 else:149 wrapper = NSIndexSetUnknown_SummaryProvider(valobj, class_data.sys_params)150 statistics.metric_hit(151 "unknown_class", valobj.GetName() + " seen as " + name_string152 )153 return wrapper154 155 156def NSIndexSet_SummaryProvider(valobj, dict):157 logger = lldb.formatters.Logger.Logger()158 provider = GetSummary_Impl(valobj)159 if provider is not None:160 if isinstance(161 provider, lldb.runtime.objc.objc_runtime.SpecialSituation_Description162 ):163 return provider.message()164 try:165 summary = provider.count()166 except:167 summary = None168 logger >> "got summary " + str(summary)169 if summary is None:170 summary = "<variable is not NSIndexSet>"171 if isinstance(summary, str):172 return summary173 else:174 summary = str(summary) + (" indexes" if summary != 1 else " index")175 return summary176 return "Summary Unavailable"177 178 179def __lldb_init_module(debugger, dict):180 debugger.HandleCommand(181 "type summary add -F NSIndexSet.NSIndexSet_SummaryProvider NSIndexSet NSMutableIndexSet"182 )183