"""
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 struct
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 NSTaggedNumber_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, info_bits, data, params):
logger = lldb.formatters.Logger.Logger()
self.valobj = valobj;
self.sys_params = params
self.info_bits = info_bits
self.data = data
self.update();
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture();
def value(self):
logger = lldb.formatters.Logger.Logger()
if self.info_bits == 0:
return '(char)' + str(ord(ctypes.c_char(chr(self.data % 256)).value))
if self.info_bits == 4:
return '(short)' + str(ctypes.c_short(self.data % (256*256)).value)
if self.info_bits == 8:
return '(int)' + str(ctypes.c_int(self.data % (256*256*256*256)).value)
if self.info_bits == 12:
return '(long)' + str(ctypes.c_long(self.data).value)
else:
return 'unexpected value:(info=' + str(self.info_bits) + ", value = " + str(self.data) + ')'
class NSUntaggedNumber_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.char):
self.sys_params.types_cache.char = self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar)
if not(self.sys_params.types_cache.short):
self.sys_params.types_cache.short = self.valobj.GetType().GetBasicType(lldb.eBasicTypeShort)
if not(self.sys_params.types_cache.ushort):
self.sys_params.types_cache.ushort = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedShort)
if not(self.sys_params.types_cache.int):
self.sys_params.types_cache.int = self.valobj.GetType().GetBasicType(lldb.eBasicTypeInt)
if not(self.sys_params.types_cache.long):
self.sys_params.types_cache.long = self.valobj.GetType().GetBasicType(lldb.eBasicTypeLong)
if not(self.sys_params.types_cache.ulong):
self.sys_params.types_cache.ulong = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
if not(self.sys_params.types_cache.longlong):
self.sys_params.types_cache.longlong = self.valobj.GetType().GetBasicType(lldb.eBasicTypeLongLong)
if not(self.sys_params.types_cache.ulonglong):
self.sys_params.types_cache.ulonglong = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLongLong)
if not(self.sys_params.types_cache.float):
self.sys_params.types_cache.float = self.valobj.GetType().GetBasicType(lldb.eBasicTypeFloat)
if not(self.sys_params.types_cache.double):
self.sys_params.types_cache.double = self.valobj.GetType().GetBasicType(lldb.eBasicTypeDouble)
self.update();
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture();
def value(self):
logger = lldb.formatters.Logger.Logger()
global statistics
data_type_vo = self.valobj.CreateChildAtOffset("dt",
self.sys_params.pointer_size,
self.sys_params.types_cache.char)
data_type = ((data_type_vo.GetValueAsUnsigned(0) % 256) & 0x1F)
data_offset = 2 * self.sys_params.pointer_size
if data_type == 0B00001:
data_vo = self.valobj.CreateChildAtOffset("data",
data_offset,
self.sys_params.types_cache.char)
statistics.metric_hit('code_notrun',self.valobj)
return '(char)' + str(ord(ctypes.c_char(chr(data_vo.GetValueAsUnsigned(0))).value))
elif data_type == 0B0010:
data_vo = self.valobj.CreateChildAtOffset("data",
data_offset,
self.sys_params.types_cache.short)
statistics.metric_hit('code_notrun',self.valobj)
return '(short)' + str(ctypes.c_short(data_vo.GetValueAsUnsigned(0) % (256*256)).value)
elif data_type == 0B0011:
data_vo = self.valobj.CreateChildAtOffset("data",
data_offset,
self.sys_params.types_cache.int)
statistics.metric_hit('code_notrun',self.valobj)
return '(int)' + str(ctypes.c_int(data_vo.GetValueAsUnsigned(0)% (256*256*256*256)).value)
elif data_type == 0B10001:
data_offset = data_offset + 8 data_vo = self.valobj.CreateChildAtOffset("data",
data_offset,
self.sys_params.types_cache.longlong)
statistics.metric_hit('code_notrun',self.valobj)
return '(long)' + str(ctypes.c_long(data_vo.GetValueAsUnsigned(0)).value)
elif data_type == 0B0100:
if self.sys_params.is_64_bit:
data_offset = data_offset + self.sys_params.pointer_size
data_vo = self.valobj.CreateChildAtOffset("data",
data_offset,
self.sys_params.types_cache.longlong)
statistics.metric_hit('code_notrun',self.valobj)
return '(long)' + str(ctypes.c_long(data_vo.GetValueAsUnsigned(0)).value)
elif data_type == 0B0101:
data_vo = self.valobj.CreateChildAtOffset("data",
data_offset,
self.sys_params.types_cache.longlong)
data_plain = int(str(data_vo.GetValueAsUnsigned(0) & 0x00000000FFFFFFFF))
packed = struct.pack('I', data_plain)
data_float = struct.unpack('f', packed)[0]
statistics.metric_hit('code_notrun',self.valobj)
return '(float)' + str(data_float)
elif data_type == 0B0110:
data_vo = self.valobj.CreateChildAtOffset("data",
data_offset,
self.sys_params.types_cache.longlong)
data_plain = data_vo.GetValueAsUnsigned(0)
data_double = struct.unpack('d', struct.pack('Q', data_plain))[0]
statistics.metric_hit('code_notrun',self.valobj)
return '(double)' + str(data_double)
statistics.metric_hit('unknown_class',str(valobj.GetName()) + " had unknown data_type " + str(data_type))
return 'unexpected: dt = ' + str(data_type)
class NSUnknownNumber_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 value(self):
logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream()
self.valobj.GetExpressionPath(stream)
expr = "(NSString*)[" + stream.GetData() + " stringValue]"
num_children_vo = self.valobj.CreateValueFromExpression("str",expr)
if num_children_vo.IsValid():
return num_children_vo.GetSummary()
return '<variable is not NSNumber>'
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 == 'NSNumber' or name_string == '__NSCFNumber':
if class_data.is_tagged():
wrapper = NSTaggedNumber_SummaryProvider(valobj,class_data.info_bits(),class_data.value(), class_data.sys_params)
statistics.metric_hit('code_notrun',valobj)
else:
wrapper = NSUntaggedNumber_SummaryProvider(valobj, class_data.sys_params)
else:
wrapper = NSUnknownNumber_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
return wrapper;
def NSNumber_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.value();
except Exception as foo:
print foo
summary = None
logger >> "got summary " + str(summary)
if summary == None:
summary = '<variable is not NSNumber>'
return str(summary)
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict):
debugger.HandleCommand("type summary add -F NSNumber.NSNumber_SummaryProvider NSNumber")
debugger.HandleCommand("type summary add -F NSNumber.NSNumber_SummaryProvider __NSCFBoolean")
debugger.HandleCommand("type summary add -F NSNumber.NSNumber_SummaryProvider __NSCFNumber")