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# summary provider for NSURL 9*061da546Spatrickimport lldb 10*061da546Spatrickimport ctypes 11*061da546Spatrickimport lldb.runtime.objc.objc_runtime 12*061da546Spatrickimport lldb.formatters.metrics 13*061da546Spatrickimport CFString 14*061da546Spatrickimport lldb.formatters.Logger 15*061da546Spatrick 16*061da546Spatrickstatistics = lldb.formatters.metrics.Metrics() 17*061da546Spatrickstatistics.add_metric('invalid_isa') 18*061da546Spatrickstatistics.add_metric('invalid_pointer') 19*061da546Spatrickstatistics.add_metric('unknown_class') 20*061da546Spatrickstatistics.add_metric('code_notrun') 21*061da546Spatrick 22*061da546Spatrick# despite the similary to synthetic children providers, these classes are not 23*061da546Spatrick# trying to provide anything but a summary for an NSURL, so they need not 24*061da546Spatrick# obey the interface specification for synthetic children providers 25*061da546Spatrick 26*061da546Spatrick 27*061da546Spatrickclass NSURLKnown_SummaryProvider: 28*061da546Spatrick 29*061da546Spatrick def adjust_for_architecture(self): 30*061da546Spatrick pass 31*061da546Spatrick 32*061da546Spatrick def __init__(self, valobj, params): 33*061da546Spatrick logger = lldb.formatters.Logger.Logger() 34*061da546Spatrick self.valobj = valobj 35*061da546Spatrick self.sys_params = params 36*061da546Spatrick if not(self.sys_params.types_cache.NSString): 37*061da546Spatrick self.sys_params.types_cache.NSString = self.valobj.GetTarget( 38*061da546Spatrick ).FindFirstType('NSString').GetPointerType() 39*061da546Spatrick if not(self.sys_params.types_cache.NSURL): 40*061da546Spatrick self.sys_params.types_cache.NSURL = self.valobj.GetTarget( 41*061da546Spatrick ).FindFirstType('NSURL').GetPointerType() 42*061da546Spatrick self.update() 43*061da546Spatrick 44*061da546Spatrick def update(self): 45*061da546Spatrick logger = lldb.formatters.Logger.Logger() 46*061da546Spatrick self.adjust_for_architecture() 47*061da546Spatrick 48*061da546Spatrick # one pointer is the ISA 49*061da546Spatrick # then there is one more pointer and 8 bytes of plain data 50*061da546Spatrick # (which are also present on a 32-bit system) 51*061da546Spatrick # then there is a pointer to an NSString which is the url text 52*061da546Spatrick # optionally, the next pointer is another NSURL which is the "base" 53*061da546Spatrick # of this one when doing NSURLs composition (incidentally, NSURLs can 54*061da546Spatrick # recurse the base+text mechanism to any desired depth) 55*061da546Spatrick def offset_text(self): 56*061da546Spatrick logger = lldb.formatters.Logger.Logger() 57*061da546Spatrick return 24 if self.sys_params.is_64_bit else 16 58*061da546Spatrick 59*061da546Spatrick def offset_base(self): 60*061da546Spatrick logger = lldb.formatters.Logger.Logger() 61*061da546Spatrick return self.offset_text() + self.sys_params.pointer_size 62*061da546Spatrick 63*061da546Spatrick def url_text(self): 64*061da546Spatrick logger = lldb.formatters.Logger.Logger() 65*061da546Spatrick text = self.valobj.CreateChildAtOffset( 66*061da546Spatrick "text", self.offset_text(), self.sys_params.types_cache.NSString) 67*061da546Spatrick base = self.valobj.CreateChildAtOffset( 68*061da546Spatrick "base", self.offset_base(), self.sys_params.types_cache.NSURL) 69*061da546Spatrick my_string = CFString.CFString_SummaryProvider(text, None) 70*061da546Spatrick if len(my_string) > 0 and base.GetValueAsUnsigned(0) != 0: 71*061da546Spatrick # remove final " from myself 72*061da546Spatrick my_string = my_string[0:len(my_string) - 1] 73*061da546Spatrick my_string = my_string + ' -- ' 74*061da546Spatrick my_base_string = NSURL_SummaryProvider(base, None) 75*061da546Spatrick if len(my_base_string) > 2: 76*061da546Spatrick # remove @" marker from base URL string 77*061da546Spatrick my_base_string = my_base_string[2:] 78*061da546Spatrick my_string = my_string + my_base_string 79*061da546Spatrick return my_string 80*061da546Spatrick 81*061da546Spatrick 82*061da546Spatrickclass NSURLUnknown_SummaryProvider: 83*061da546Spatrick 84*061da546Spatrick def adjust_for_architecture(self): 85*061da546Spatrick pass 86*061da546Spatrick 87*061da546Spatrick def __init__(self, valobj, params): 88*061da546Spatrick logger = lldb.formatters.Logger.Logger() 89*061da546Spatrick self.valobj = valobj 90*061da546Spatrick self.sys_params = params 91*061da546Spatrick self.update() 92*061da546Spatrick 93*061da546Spatrick def update(self): 94*061da546Spatrick logger = lldb.formatters.Logger.Logger() 95*061da546Spatrick self.adjust_for_architecture() 96*061da546Spatrick 97*061da546Spatrick def url_text(self): 98*061da546Spatrick logger = lldb.formatters.Logger.Logger() 99*061da546Spatrick stream = lldb.SBStream() 100*061da546Spatrick self.valobj.GetExpressionPath(stream) 101*061da546Spatrick url_text_vo = self.valobj.CreateValueFromExpression( 102*061da546Spatrick "url", "(NSString*)[" + stream.GetData() + " description]") 103*061da546Spatrick if url_text_vo.IsValid(): 104*061da546Spatrick return CFString.CFString_SummaryProvider(url_text_vo, None) 105*061da546Spatrick return '<variable is not NSURL>' 106*061da546Spatrick 107*061da546Spatrick 108*061da546Spatrickdef GetSummary_Impl(valobj): 109*061da546Spatrick logger = lldb.formatters.Logger.Logger() 110*061da546Spatrick global statistics 111*061da546Spatrick class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( 112*061da546Spatrick valobj, statistics) 113*061da546Spatrick if wrapper: 114*061da546Spatrick return wrapper 115*061da546Spatrick 116*061da546Spatrick name_string = class_data.class_name() 117*061da546Spatrick logger >> "class name is: " + str(name_string) 118*061da546Spatrick 119*061da546Spatrick if name_string == 'NSURL': 120*061da546Spatrick wrapper = NSURLKnown_SummaryProvider(valobj, class_data.sys_params) 121*061da546Spatrick statistics.metric_hit('code_notrun', valobj) 122*061da546Spatrick else: 123*061da546Spatrick wrapper = NSURLUnknown_SummaryProvider(valobj, class_data.sys_params) 124*061da546Spatrick statistics.metric_hit( 125*061da546Spatrick 'unknown_class', 126*061da546Spatrick valobj.GetName() + 127*061da546Spatrick " seen as " + 128*061da546Spatrick name_string) 129*061da546Spatrick return wrapper 130*061da546Spatrick 131*061da546Spatrick 132*061da546Spatrickdef NSURL_SummaryProvider(valobj, dict): 133*061da546Spatrick logger = lldb.formatters.Logger.Logger() 134*061da546Spatrick provider = GetSummary_Impl(valobj) 135*061da546Spatrick if provider is not None: 136*061da546Spatrick if isinstance( 137*061da546Spatrick provider, 138*061da546Spatrick lldb.runtime.objc.objc_runtime.SpecialSituation_Description): 139*061da546Spatrick return provider.message() 140*061da546Spatrick try: 141*061da546Spatrick summary = provider.url_text() 142*061da546Spatrick except: 143*061da546Spatrick summary = None 144*061da546Spatrick logger >> "got summary " + str(summary) 145*061da546Spatrick if summary is None or summary == '': 146*061da546Spatrick summary = '<variable is not NSURL>' 147*061da546Spatrick return summary 148*061da546Spatrick return 'Summary Unavailable' 149*061da546Spatrick 150*061da546Spatrick 151*061da546Spatrickdef __lldb_init_module(debugger, dict): 152*061da546Spatrick debugger.HandleCommand( 153*061da546Spatrick "type summary add -F NSURL.NSURL_SummaryProvider NSURL CFURLRef") 154