Newer
Older
Enrico Granata
committed
# summary provider for NSData
import lldb
import ctypes
import objc_runtime
import metrics
statistics = metrics.Metrics()
statistics.add_metric('invalid_isa')
statistics.add_metric('invalid_pointer')
statistics.add_metric('unknown_class')
statistics.add_metric('code_notrun')
# despite the similary to synthetic children providers, these classes are not
# trying to provide anything but the length for an NSData, so they need not
# obey the interface specification for synthetic children providers
class NSConcreteData_SummaryProvider:
def adjust_for_architecture(self):
self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8)
Enrico Granata
committed
self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle)
self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize()
def __init__(self, valobj):
self.valobj = valobj;
self.update();
def update(self):
self.adjust_for_architecture();
self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID)
Enrico Granata
committed
self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
# one pointer is the ISA
# then there are 32 bit worth of flags and other data
# however, on 64bit systems these are padded to be a full
# machine word long, which means we actually have two pointers
# worth of data to skip
def offset(self):
Enrico Granata
committed
return 16
else:
return 8
def length(self):
size = self.valobj.CreateChildAtOffset("count",
self.offset(),
self.NSUInteger)
return size.GetValueAsUnsigned(0)
class NSDataUnknown_SummaryProvider:
def adjust_for_architecture(self):
self.is_64_bit = (self.valobj.GetTarget().GetProcess().GetAddressByteSize() == 8)
Enrico Granata
committed
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
self.is_little = (self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle)
self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize()
def __init__(self, valobj):
self.valobj = valobj;
self.update()
def update(self):
self.adjust_for_architecture();
self.id_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID)
def length(self):
stream = lldb.SBStream()
self.valobj.GetExpressionPath(stream)
num_children_vo = self.valobj.CreateValueFromExpression("count","(int)[" + stream.GetData() + " length]");
return num_children_vo.GetValueAsUnsigned(0)
def GetSummary_Impl(valobj):
global statistics
class_data = objc_runtime.ObjCRuntime(valobj)
if class_data.is_valid() == False:
statistics.metric_hit('invalid_pointer',valobj)
wrapper = None
return
class_data = class_data.read_class_data()
if class_data.is_valid() == False:
statistics.metric_hit('invalid_isa',valobj)
wrapper = None
return
if class_data.is_kvo():
class_data = class_data.get_superclass()
if class_data.is_valid() == False:
statistics.metric_hit('invalid_isa',valobj)
wrapper = None
return
name_string = class_data.class_name()
if name_string == 'NSConcreteData' or \
name_string == 'NSConcreteMutableData' or \
name_string == '__NSCFData':
wrapper = NSConcreteData_SummaryProvider(valobj)
statistics.metric_hit('code_notrun',valobj)
else:
wrapper = NSDataUnknown_SummaryProvider(valobj)
statistics.metric_hit('unknown_class',str(valobj) + " seen as " + name_string)
return wrapper;
def NSData_SummaryProvider (valobj,dict):
provider = GetSummary_Impl(valobj);
if provider != None:
try:
summary = provider.length();
except:
summary = None
if summary == None:
summary = 'no valid data here'
if summary == 1:
return '1 byte'
return str(summary) + " bytes"
return ''
def __lldb_init_module(debugger,dict):
debugger.HandleCommand("type summary add -F NSData.NSData_SummaryProvider NSData CFDataRef CFMutableDataRef")