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