diff options
Diffstat (limited to 'examples/summaries/cocoa/CFArray.py')
-rw-r--r-- | examples/summaries/cocoa/CFArray.py | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/examples/summaries/cocoa/CFArray.py b/examples/summaries/cocoa/CFArray.py new file mode 100644 index 0000000000000..5068875b5b38e --- /dev/null +++ b/examples/summaries/cocoa/CFArray.py @@ -0,0 +1,204 @@ +""" +LLDB AppKit formatters + +part of The LLVM Compiler Infrastructure +This file is distributed under the University of Illinois Open Source +License. See LICENSE.TXT for details. +""" +# example summary provider for NSArray +# the real summary is now C++ code built into LLDB +import lldb +import ctypes +import lldb.runtime.objc.objc_runtime +import lldb.formatters.metrics +import lldb.formatters.Logger + +statistics = lldb.formatters.metrics.Metrics() +statistics.add_metric('invalid_isa') +statistics.add_metric('invalid_pointer') +statistics.add_metric('unknown_class') +statistics.add_metric('code_notrun') + +# much less functional than the other two cases below +# just runs code to get to the count and then returns +# no children +class NSArrayKVC_SynthProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, dict, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj; + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture(); + + def num_children(self): + logger = lldb.formatters.Logger.Logger() + stream = lldb.SBStream() + self.valobj.GetExpressionPath(stream) + num_children_vo = self.valobj.CreateValueFromExpression("count","(int)[" + stream.GetData() + " count]"); + if num_children_vo.IsValid(): + return num_children_vo.GetValueAsUnsigned(0) + return "<variable is not NSArray>" + +# much less functional than the other two cases below +# just runs code to get to the count and then returns +# no children +class NSArrayCF_SynthProvider: + + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, dict, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj; + self.sys_params = params + if not (self.sys_params.types_cache.ulong): + self.sys_params.types_cache.ulong = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture(); + + def num_children(self): + logger = lldb.formatters.Logger.Logger() + num_children_vo = self.valobj.CreateChildAtOffset("count", + self.sys_params.cfruntime_size, + self.sys_params.types_cache.ulong) + return num_children_vo.GetValueAsUnsigned(0) + +class NSArrayI_SynthProvider: + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, dict, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj; + self.sys_params = params + if not(self.sys_params.types_cache.long): + self.sys_params.types_cache.long = self.valobj.GetType().GetBasicType(lldb.eBasicTypeLong) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture(); + + # skip the isa pointer and get at the size + def num_children(self): + logger = lldb.formatters.Logger.Logger() + count = self.valobj.CreateChildAtOffset("count", + self.sys_params.pointer_size, + self.sys_params.types_cache.long); + return count.GetValueAsUnsigned(0) + +class NSArrayM_SynthProvider: + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, dict, params): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj; + self.sys_params = params + if not(self.sys_params.types_cache.long): + self.sys_params.types_cache.long = self.valobj.GetType().GetBasicType(lldb.eBasicTypeLong) + self.update() + + def update(self): + logger = lldb.formatters.Logger.Logger() + self.adjust_for_architecture(); + + # skip the isa pointer and get at the size + def num_children(self): + logger = lldb.formatters.Logger.Logger() + count = self.valobj.CreateChildAtOffset("count", + self.sys_params.pointer_size, + self.sys_params.types_cache.long); + return count.GetValueAsUnsigned(0) + +# this is the actual synth provider, but is just a wrapper that checks +# whether valobj is an instance of __NSArrayI or __NSArrayM and sets up an +# appropriate backend layer to do the computations +class NSArray_SynthProvider: + def adjust_for_architecture(self): + pass + + def __init__(self, valobj, dict): + logger = lldb.formatters.Logger.Logger() + self.valobj = valobj; + self.adjust_for_architecture() + self.error = False + self.wrapper = self.make_wrapper() + self.invalid = (self.wrapper == None) + + def num_children(self): + logger = lldb.formatters.Logger.Logger() + if self.wrapper == None: + return 0; + return self.wrapper.num_children() + + def update(self): + logger = lldb.formatters.Logger.Logger() + if self.wrapper == None: + return + self.wrapper.update() + + # this code acts as our defense against NULL and uninitialized + # NSArray pointers, which makes it much longer than it would be otherwise + def make_wrapper(self): + logger = lldb.formatters.Logger.Logger() + if self.valobj.GetValueAsUnsigned() == 0: + self.error = True + return lldb.runtime.objc.objc_runtime.InvalidPointer_Description(True) + else: + global statistics + class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(self.valobj,statistics) + if wrapper: + self.error = True + return wrapper + + name_string = class_data.class_name() + + logger >> "Class name is " + str(name_string) + + if name_string == '__NSArrayI': + wrapper = NSArrayI_SynthProvider(self.valobj, dict, class_data.sys_params) + statistics.metric_hit('code_notrun',self.valobj.GetName()) + elif name_string == '__NSArrayM': + wrapper = NSArrayM_SynthProvider(self.valobj, dict, class_data.sys_params) + statistics.metric_hit('code_notrun',self.valobj.GetName()) + elif name_string == '__NSCFArray': + wrapper = NSArrayCF_SynthProvider(self.valobj, dict, class_data.sys_params) + statistics.metric_hit('code_notrun',self.valobj.GetName()) + else: + wrapper = NSArrayKVC_SynthProvider(self.valobj, dict, class_data.sys_params) + statistics.metric_hit('unknown_class',str(self.valobj.GetName()) + " seen as " + name_string) + return wrapper; + +def CFArray_SummaryProvider (valobj,dict): + logger = lldb.formatters.Logger.Logger() + provider = NSArray_SynthProvider(valobj,dict); + if provider.invalid == False: + if provider.error == True: + return provider.wrapper.message() + try: + summary = int(provider.num_children()); + except: + summary = None + logger >> "provider gave me " + str(summary) + if summary == None: + summary = '<variable is not NSArray>' + elif isinstance(summary,basestring): + pass + else: + # we format it like it were a CFString to make it look the same as the summary from Xcode + summary = '@"' + str(summary) + (" objects" if summary != 1 else " object") + '"' + return summary + return 'Summary Unavailable' + +def __lldb_init_module(debugger,dict): + debugger.HandleCommand("type summary add -F CFArray.CFArray_SummaryProvider NSArray CFArrayRef CFMutableArrayRef") |