150 lines · python
1"""2LLDB AppKit formatters3 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-exception7"""8# example summary provider for NSBundle9# the real summary is now C++ code built into LLDB10import lldb11import ctypes12import lldb.runtime.objc.objc_runtime13import lldb.formatters.metrics14import NSURL15import lldb.formatters.Logger16 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 not24# trying to provide anything but a summary for an NSURL, so they need not25# obey the interface specification for synthetic children providers26 27 28class NSBundleKnown_SummaryProvider:29 def adjust_for_architecture(self):30 pass31 32 def __init__(self, valobj, params):33 logger = lldb.formatters.Logger.Logger()34 self.valobj = valobj35 self.sys_params = params36 if not (self.sys_params.types_cache.NSString):37 self.sys_params.types_cache.NSString = (38 self.valobj.GetTarget().FindFirstType("NSString").GetPointerType()39 )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 values47 # that are luckily each a pointer in size48 # which makes our computation trivial :-)49 def offset(self):50 logger = lldb.formatters.Logger.Logger()51 return 5 * self.sys_params.pointer_size52 53 def url_text(self):54 logger = lldb.formatters.Logger.Logger()55 global statistics56 text = self.valobj.CreateChildAtOffset(57 "text", self.offset(), self.sys_params.types_cache.NSString58 )59 my_string = text.GetSummary()60 if (my_string is None) or (my_string == ""):61 statistics.metric_hit(62 "unknown_class",63 str(self.valobj.GetName()) + " triggered unknown pointer location",64 )65 return NSBundleUnknown_SummaryProvider(66 self.valobj, self.sys_params67 ).url_text()68 else:69 statistics.metric_hit("code_notrun", self.valobj)70 return my_string71 72 73class NSBundleUnknown_SummaryProvider:74 def adjust_for_architecture(self):75 pass76 77 def __init__(self, valobj, params):78 logger = lldb.formatters.Logger.Logger()79 self.valobj = valobj80 self.sys_params = params81 self.update()82 83 def update(self):84 logger = lldb.formatters.Logger.Logger()85 self.adjust_for_architecture()86 87 def url_text(self):88 logger = lldb.formatters.Logger.Logger()89 stream = lldb.SBStream()90 self.valobj.GetExpressionPath(stream)91 expr = "(NSString*)[" + stream.GetData() + " bundlePath]"92 url_text_vo = self.valobj.CreateValueFromExpression("path", expr)93 if url_text_vo.IsValid():94 return url_text_vo.GetSummary()95 return "<variable is not NSBundle>"96 97 98def GetSummary_Impl(valobj):99 logger = lldb.formatters.Logger.Logger()100 global statistics101 (102 class_data,103 wrapper,104 ) = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(105 valobj, statistics106 )107 if wrapper:108 return wrapper109 110 name_string = class_data.class_name()111 logger >> "class name is: " + str(name_string)112 113 if name_string == "NSBundle":114 wrapper = NSBundleKnown_SummaryProvider(valobj, class_data.sys_params)115 # [NSBundle mainBundle] does return an object that is116 # not correctly filled out for our purposes, so we still117 # end up having to run code in that case118 # statistics.metric_hit('code_notrun',valobj)119 else:120 wrapper = NSBundleUnknown_SummaryProvider(valobj, class_data.sys_params)121 statistics.metric_hit(122 "unknown_class", valobj.GetName() + " seen as " + name_string123 )124 return wrapper125 126 127def NSBundle_SummaryProvider(valobj, dict):128 logger = lldb.formatters.Logger.Logger()129 provider = GetSummary_Impl(valobj)130 if provider is not None:131 if isinstance(132 provider, lldb.runtime.objc.objc_runtime.SpecialSituation_Description133 ):134 return provider.message()135 try:136 summary = provider.url_text()137 except:138 summary = None139 logger >> "got summary " + str(summary)140 if summary is None or summary == "":141 summary = "<variable is not NSBundle>"142 return summary143 return "Summary Unavailable"144 145 146def __lldb_init_module(debugger, dict):147 debugger.HandleCommand(148 "type summary add -F NSBundle.NSBundle_SummaryProvider NSBundle"149 )150