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