"""
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.
"""
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')
class NSCFDictionary_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger()
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update();
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture();
def offset(self):
logger = lldb.formatters.Logger.Logger()
if self.sys_params.is_64_bit:
return 20
else:
return 12
def num_children(self):
logger = lldb.formatters.Logger.Logger()
num_children_vo = self.valobj.CreateChildAtOffset("count",
self.offset(),
self.sys_params.types_cache.NSUInteger)
return num_children_vo.GetValueAsUnsigned(0)
class NSDictionaryI_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger()
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update();
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture();
def offset(self):
logger = lldb.formatters.Logger.Logger()
return self.sys_params.pointer_size
def num_children(self):
logger = lldb.formatters.Logger.Logger()
num_children_vo = self.valobj.CreateChildAtOffset("count",
self.offset(),
self.sys_params.types_cache.NSUInteger)
value = num_children_vo.GetValueAsUnsigned(0)
if value != None:
if self.sys_params.is_64_bit:
value = value & ~0xFC00000000000000
else:
value = value & ~0xFC000000
return value
class NSDictionaryM_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger()
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update();
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture();
def offset(self):
return self.sys_params.pointer_size
def num_children(self):
logger = lldb.formatters.Logger.Logger()
num_children_vo = self.valobj.CreateChildAtOffset("count",
self.offset(),
self.sys_params.types_cache.NSUInteger)
value = num_children_vo.GetValueAsUnsigned(0)
if value != None:
if self.sys_params.is_64_bit:
value = value & ~0xFC00000000000000
else:
value = value & ~0xFC000000
return value
class NSDictionaryUnknown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger()
self.valobj = valobj;
self.sys_params = params
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 NSDictionary>'
def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger()
global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics)
if wrapper:
return wrapper
name_string = class_data.class_name()
logger >> "class name is: " + str(name_string)
if name_string == '__NSCFDictionary':
wrapper = NSCFDictionary_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun',valobj)
elif name_string == '__NSDictionaryI':
wrapper = NSDictionaryI_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun',valobj)
elif name_string == '__NSDictionaryM':
wrapper = NSDictionaryM_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun',valobj)
else:
wrapper = NSDictionaryUnknown_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
return wrapper;
def CFDictionary_SummaryProvider (valobj,dict):
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj);
if provider != None:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.num_children();
except:
summary = None
logger >> "got summary " + str(summary)
if summary == None:
return '<variable is not NSDictionary>'
if isinstance(summary,basestring):
return summary
return str(summary) + (" key/value pairs" if summary != 1 else " key/value pair")
return 'Summary Unavailable'
def CFDictionary_SummaryProvider2 (valobj,dict):
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj);
if provider != None:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.num_children();
except:
summary = None
logger >> "got summary " + str(summary)
if summary == None:
summary = '<variable is not CFDictionary>'
if isinstance(summary,basestring):
return summary
else:
if provider.sys_params.is_64_bit:
summary = summary & ~0x0f1f000000000000
summary = '@"' + str(summary) + (' entries"' if summary != 1 else ' entry"')
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict):
debugger.HandleCommand("type summary add -F CFDictionary.CFDictionary_SummaryProvider NSDictionary")
debugger.HandleCommand("type summary add -F CFDictionary.CFDictionary_SummaryProvider2 CFDictionaryRef CFMutableDictionaryRef")