1*061da546Spatrick""" 2*061da546SpatrickLLDB AppKit formatters 3*061da546Spatrick 4*061da546SpatrickPart of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5*061da546SpatrickSee https://llvm.org/LICENSE.txt for license information. 6*061da546SpatrickSPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7*061da546Spatrick""" 8*061da546Spatrick# example summary provider for NSBundle 9*061da546Spatrick# the real summary is now C++ code built into LLDB 10*061da546Spatrickimport lldb 11*061da546Spatrickimport ctypes 12*061da546Spatrickimport lldb.runtime.objc.objc_runtime 13*061da546Spatrickimport lldb.formatters.metrics 14*061da546Spatrickimport NSURL 15*061da546Spatrickimport lldb.formatters.Logger 16*061da546Spatrick 17*061da546Spatrickstatistics = lldb.formatters.metrics.Metrics() 18*061da546Spatrickstatistics.add_metric('invalid_isa') 19*061da546Spatrickstatistics.add_metric('invalid_pointer') 20*061da546Spatrickstatistics.add_metric('unknown_class') 21*061da546Spatrickstatistics.add_metric('code_notrun') 22*061da546Spatrick 23*061da546Spatrick# despite the similary to synthetic children providers, these classes are not 24*061da546Spatrick# trying to provide anything but a summary for an NSURL, so they need not 25*061da546Spatrick# obey the interface specification for synthetic children providers 26*061da546Spatrick 27*061da546Spatrick 28*061da546Spatrickclass NSBundleKnown_SummaryProvider: 29*061da546Spatrick 30*061da546Spatrick def adjust_for_architecture(self): 31*061da546Spatrick pass 32*061da546Spatrick 33*061da546Spatrick def __init__(self, valobj, params): 34*061da546Spatrick logger = lldb.formatters.Logger.Logger() 35*061da546Spatrick self.valobj = valobj 36*061da546Spatrick self.sys_params = params 37*061da546Spatrick if not(self.sys_params.types_cache.NSString): 38*061da546Spatrick self.sys_params.types_cache.NSString = self.valobj.GetTarget( 39*061da546Spatrick ).FindFirstType('NSString').GetPointerType() 40*061da546Spatrick self.update() 41*061da546Spatrick 42*061da546Spatrick def update(self): 43*061da546Spatrick logger = lldb.formatters.Logger.Logger() 44*061da546Spatrick self.adjust_for_architecture() 45*061da546Spatrick 46*061da546Spatrick # we need to skip the ISA, plus four other values 47*061da546Spatrick # that are luckily each a pointer in size 48*061da546Spatrick # which makes our computation trivial :-) 49*061da546Spatrick def offset(self): 50*061da546Spatrick logger = lldb.formatters.Logger.Logger() 51*061da546Spatrick return 5 * self.sys_params.pointer_size 52*061da546Spatrick 53*061da546Spatrick def url_text(self): 54*061da546Spatrick logger = lldb.formatters.Logger.Logger() 55*061da546Spatrick global statistics 56*061da546Spatrick text = self.valobj.CreateChildAtOffset( 57*061da546Spatrick "text", self.offset(), self.sys_params.types_cache.NSString) 58*061da546Spatrick my_string = text.GetSummary() 59*061da546Spatrick if (my_string is None) or (my_string == ''): 60*061da546Spatrick statistics.metric_hit( 61*061da546Spatrick 'unknown_class', str( 62*061da546Spatrick self.valobj.GetName()) + " triggered unknown pointer location") 63*061da546Spatrick return NSBundleUnknown_SummaryProvider( 64*061da546Spatrick self.valobj, self.sys_params).url_text() 65*061da546Spatrick else: 66*061da546Spatrick statistics.metric_hit('code_notrun', self.valobj) 67*061da546Spatrick return my_string 68*061da546Spatrick 69*061da546Spatrick 70*061da546Spatrickclass NSBundleUnknown_SummaryProvider: 71*061da546Spatrick 72*061da546Spatrick def adjust_for_architecture(self): 73*061da546Spatrick pass 74*061da546Spatrick 75*061da546Spatrick def __init__(self, valobj, params): 76*061da546Spatrick logger = lldb.formatters.Logger.Logger() 77*061da546Spatrick self.valobj = valobj 78*061da546Spatrick self.sys_params = params 79*061da546Spatrick self.update() 80*061da546Spatrick 81*061da546Spatrick def update(self): 82*061da546Spatrick logger = lldb.formatters.Logger.Logger() 83*061da546Spatrick self.adjust_for_architecture() 84*061da546Spatrick 85*061da546Spatrick def url_text(self): 86*061da546Spatrick logger = lldb.formatters.Logger.Logger() 87*061da546Spatrick stream = lldb.SBStream() 88*061da546Spatrick self.valobj.GetExpressionPath(stream) 89*061da546Spatrick expr = "(NSString*)[" + stream.GetData() + " bundlePath]" 90*061da546Spatrick url_text_vo = self.valobj.CreateValueFromExpression("path", expr) 91*061da546Spatrick if url_text_vo.IsValid(): 92*061da546Spatrick return url_text_vo.GetSummary() 93*061da546Spatrick return '<variable is not NSBundle>' 94*061da546Spatrick 95*061da546Spatrick 96*061da546Spatrickdef GetSummary_Impl(valobj): 97*061da546Spatrick logger = lldb.formatters.Logger.Logger() 98*061da546Spatrick global statistics 99*061da546Spatrick class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( 100*061da546Spatrick valobj, statistics) 101*061da546Spatrick if wrapper: 102*061da546Spatrick return wrapper 103*061da546Spatrick 104*061da546Spatrick name_string = class_data.class_name() 105*061da546Spatrick logger >> "class name is: " + str(name_string) 106*061da546Spatrick 107*061da546Spatrick if name_string == 'NSBundle': 108*061da546Spatrick wrapper = NSBundleKnown_SummaryProvider(valobj, class_data.sys_params) 109*061da546Spatrick # [NSBundle mainBundle] does return an object that is 110*061da546Spatrick # not correctly filled out for our purposes, so we still 111*061da546Spatrick # end up having to run code in that case 112*061da546Spatrick # statistics.metric_hit('code_notrun',valobj) 113*061da546Spatrick else: 114*061da546Spatrick wrapper = NSBundleUnknown_SummaryProvider( 115*061da546Spatrick valobj, class_data.sys_params) 116*061da546Spatrick statistics.metric_hit( 117*061da546Spatrick 'unknown_class', 118*061da546Spatrick valobj.GetName() + 119*061da546Spatrick " seen as " + 120*061da546Spatrick name_string) 121*061da546Spatrick return wrapper 122*061da546Spatrick 123*061da546Spatrick 124*061da546Spatrickdef NSBundle_SummaryProvider(valobj, dict): 125*061da546Spatrick logger = lldb.formatters.Logger.Logger() 126*061da546Spatrick provider = GetSummary_Impl(valobj) 127*061da546Spatrick if provider is not None: 128*061da546Spatrick if isinstance( 129*061da546Spatrick provider, 130*061da546Spatrick lldb.runtime.objc.objc_runtime.SpecialSituation_Description): 131*061da546Spatrick return provider.message() 132*061da546Spatrick try: 133*061da546Spatrick summary = provider.url_text() 134*061da546Spatrick except: 135*061da546Spatrick summary = None 136*061da546Spatrick logger >> "got summary " + str(summary) 137*061da546Spatrick if summary is None or summary == '': 138*061da546Spatrick summary = '<variable is not NSBundle>' 139*061da546Spatrick return summary 140*061da546Spatrick return 'Summary Unavailable' 141*061da546Spatrick 142*061da546Spatrick 143*061da546Spatrickdef __lldb_init_module(debugger, dict): 144*061da546Spatrick debugger.HandleCommand( 145*061da546Spatrick "type summary add -F NSBundle.NSBundle_SummaryProvider NSBundle") 146