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 NSNotification 9# the real summary is now C++ code built into LLDB 10import lldb.runtime.objc.objc_runtime 11import lldb.formatters.metrics 12import CFString 13import lldb 14import lldb.formatters.Logger 15 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 23class NSConcreteNotification_SummaryProvider: 24 def adjust_for_architecture(self): 25 pass 26 27 def __init__(self, valobj, params): 28 logger = lldb.formatters.Logger.Logger() 29 self.valobj = valobj 30 self.sys_params = params 31 if not (self.sys_params.types_cache.id): 32 self.sys_params.types_cache.id = self.valobj.GetType().GetBasicType( 33 lldb.eBasicTypeObjCID 34 ) 35 self.update() 36 37 def update(self): 38 logger = lldb.formatters.Logger.Logger() 39 self.adjust_for_architecture() 40 41 # skip the ISA and go to the name pointer 42 def offset(self): 43 logger = lldb.formatters.Logger.Logger() 44 return self.sys_params.pointer_size 45 46 def name(self): 47 logger = lldb.formatters.Logger.Logger() 48 string_ptr = self.valobj.CreateChildAtOffset( 49 "name", self.offset(), self.sys_params.types_cache.id 50 ) 51 return CFString.CFString_SummaryProvider(string_ptr, None) 52 53 54class NSNotificationUnknown_SummaryProvider: 55 def adjust_for_architecture(self): 56 pass 57 58 def __init__(self, valobj, params): 59 logger = lldb.formatters.Logger.Logger() 60 self.valobj = valobj 61 self.sys_params = params 62 self.update() 63 64 def update(self): 65 logger = lldb.formatters.Logger.Logger() 66 self.adjust_for_architecture() 67 68 def name(self): 69 logger = lldb.formatters.Logger.Logger() 70 stream = lldb.SBStream() 71 self.valobj.GetExpressionPath(stream) 72 name_vo = self.valobj.CreateValueFromExpression( 73 "name", "(NSString*)[" + stream.GetData() + " name]" 74 ) 75 if name_vo.IsValid(): 76 return CFString.CFString_SummaryProvider(name_vo, None) 77 return "<variable is not NSNotification>" 78 79 80def GetSummary_Impl(valobj): 81 logger = lldb.formatters.Logger.Logger() 82 global statistics 83 ( 84 class_data, 85 wrapper, 86 ) = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection( 87 valobj, statistics 88 ) 89 if wrapper: 90 return wrapper 91 92 name_string = class_data.class_name() 93 logger >> "class name is: " + str(name_string) 94 95 if name_string == "NSConcreteNotification": 96 wrapper = NSConcreteNotification_SummaryProvider(valobj, class_data.sys_params) 97 statistics.metric_hit("code_notrun", valobj) 98 else: 99 wrapper = NSNotificationUnknown_SummaryProvider(valobj, class_data.sys_params) 100 statistics.metric_hit( 101 "unknown_class", valobj.GetName() + " seen as " + name_string 102 ) 103 return wrapper 104 105 106def NSNotification_SummaryProvider(valobj, dict): 107 logger = lldb.formatters.Logger.Logger() 108 provider = GetSummary_Impl(valobj) 109 if provider is not None: 110 if isinstance( 111 provider, lldb.runtime.objc.objc_runtime.SpecialSituation_Description 112 ): 113 return provider.message() 114 try: 115 summary = provider.name() 116 except: 117 summary = None 118 logger >> "got summary " + str(summary) 119 if summary is None: 120 summary = "<variable is not NSNotification>" 121 return str(summary) 122 return "Summary Unavailable" 123 124 125def __lldb_init_module(debugger, dict): 126 debugger.HandleCommand( 127 "type summary add -F NSNotification.NSNotification_SummaryProvider NSNotification" 128 ) 129