190 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 NSData9# 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 length for an NSData, so they need not24# obey the interface specification for synthetic children providers25 26 27class NSConcreteData_SummaryProvider:28 def adjust_for_architecture(self):29 pass30 31 def __init__(self, valobj, params):32 logger = lldb.formatters.Logger.Logger()33 logger >> "NSConcreteData_SummaryProvider __init__"34 self.valobj = valobj35 self.sys_params = params36 if not (self.sys_params.types_cache.NSUInteger):37 if self.sys_params.is_64_bit:38 self.sys_params.types_cache.NSUInteger = (39 self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)40 )41 else:42 self.sys_params.types_cache.NSUInteger = (43 self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)44 )45 self.update()46 47 def update(self):48 self.adjust_for_architecture()49 50 # one pointer is the ISA51 # then there are 32 bit worth of flags and other data52 # however, on 64bit systems these are padded to be a full53 # machine word long, which means we actually have two pointers54 # worth of data to skip55 def offset(self):56 return 2 * self.sys_params.pointer_size57 58 def length(self):59 logger = lldb.formatters.Logger.Logger()60 logger >> "NSConcreteData_SummaryProvider length"61 size = self.valobj.CreateChildAtOffset(62 "count", self.offset(), self.sys_params.types_cache.NSUInteger63 )64 logger >> str(size)65 logger >> str(size.GetValueAsUnsigned(0))66 return size.GetValueAsUnsigned(0)67 68 69class NSDataUnknown_SummaryProvider:70 def adjust_for_architecture(self):71 pass72 73 def __init__(self, valobj, params):74 logger = lldb.formatters.Logger.Logger()75 logger >> "NSDataUnknown_SummaryProvider __init__"76 self.valobj = valobj77 self.sys_params = params78 self.update()79 80 def update(self):81 self.adjust_for_architecture()82 83 def length(self):84 logger = lldb.formatters.Logger.Logger()85 logger >> "NSDataUnknown_SummaryProvider length"86 stream = lldb.SBStream()87 self.valobj.GetExpressionPath(stream)88 logger >> stream.GetData()89 num_children_vo = self.valobj.CreateValueFromExpression(90 "count", "(int)[" + stream.GetData() + " length]"91 )92 logger >> "still in after expression: " + str(num_children_vo)93 if num_children_vo.IsValid():94 logger >> "wow - expr output is valid: " + str(95 num_children_vo.GetValueAsUnsigned()96 )97 return num_children_vo.GetValueAsUnsigned(0)98 logger >> "invalid expr output - too bad"99 return "<variable is not NSData>"100 101 102def GetSummary_Impl(valobj):103 global statistics104 logger = lldb.formatters.Logger.Logger()105 logger >> "NSData GetSummary_Impl"106 (107 class_data,108 wrapper,109 ) = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(110 valobj, statistics111 )112 if wrapper:113 logger >> "got a wrapper summary - using it"114 return wrapper115 116 name_string = class_data.class_name()117 logger >> "class name: " + name_string118 if (119 name_string == "NSConcreteData"120 or name_string == "NSConcreteMutableData"121 or name_string == "__NSCFData"122 ):123 wrapper = NSConcreteData_SummaryProvider(valobj, class_data.sys_params)124 statistics.metric_hit("code_notrun", valobj)125 else:126 wrapper = NSDataUnknown_SummaryProvider(valobj, class_data.sys_params)127 statistics.metric_hit(128 "unknown_class", valobj.GetName() + " seen as " + name_string129 )130 return wrapper131 132 133def NSData_SummaryProvider(valobj, dict):134 logger = lldb.formatters.Logger.Logger()135 logger >> "NSData_SummaryProvider"136 provider = GetSummary_Impl(valobj)137 logger >> "found a summary provider, it is: " + str(provider)138 if provider is not None:139 try:140 summary = provider.length()141 except:142 summary = None143 logger >> "got a summary: it is " + str(summary)144 if summary is None:145 summary = "<variable is not NSData>"146 elif isinstance(summary, str):147 pass148 else:149 if summary == 1:150 summary = "1 byte"151 else:152 summary = str(summary) + " bytes"153 return summary154 return "Summary Unavailable"155 156 157def NSData_SummaryProvider2(valobj, dict):158 logger = lldb.formatters.Logger.Logger()159 logger >> "NSData_SummaryProvider2"160 provider = GetSummary_Impl(valobj)161 logger >> "found a summary provider, it is: " + str(provider)162 if provider is not None:163 if isinstance(164 provider, lldb.runtime.objc.objc_runtime.SpecialSituation_Description165 ):166 return provider.message()167 try:168 summary = provider.length()169 except:170 summary = None171 logger >> "got a summary: it is " + str(summary)172 if summary is None:173 summary = "<variable is not CFData>"174 elif isinstance(summary, str):175 pass176 else:177 if summary == 1:178 summary = '@"1 byte"'179 else:180 summary = '@"' + str(summary) + ' bytes"'181 return summary182 return "Summary Unavailable"183 184 185def __lldb_init_module(debugger, dict):186 debugger.HandleCommand("type summary add -F NSData.NSData_SummaryProvider NSData")187 debugger.HandleCommand(188 "type summary add -F NSData.NSData_SummaryProvider2 CFDataRef CFMutableDataRef"189 )190