blob: 11188d045655edc58a911a8a632917c129b39f5d [file] [log] [blame]
"""
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 unitialized
# 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")