1"""
2LLDB AppKit formatters
3
4part of The LLVM Compiler Infrastructure
5This file is distributed under the University of Illinois Open Source
6License. See LICENSE.TXT for details.
7"""
8# example summary provider for NSData
9# the real summary is now C++ code built into LLDB
10import lldb
11import ctypes
12import lldb.runtime.objc.objc_runtime
13import lldb.formatters.metrics
14import lldb.formatters.Logger
15
16statistics = lldb.formatters.metrics.Metrics()
17statistics.add_metric('invalid_isa')
18statistics.add_metric('invalid_pointer')
19statistics.add_metric('unknown_class')
20statistics.add_metric('code_notrun')
21
22# despite the similary to synthetic children providers, these classes are not
23# trying to provide anything but the length for an NSData, so they need not
24# obey the interface specification for synthetic children providers
25class NSConcreteData_SummaryProvider:
26	def adjust_for_architecture(self):
27		pass
28
29	def __init__(self, valobj, params):
30		logger = lldb.formatters.Logger.Logger()
31		logger >> "NSConcreteData_SummaryProvider __init__"
32		self.valobj = valobj;
33		self.sys_params = params
34		if not(self.sys_params.types_cache.NSUInteger):
35			if self.sys_params.is_64_bit:
36				self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
37			else:
38				self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
39		self.update();
40
41	def update(self):
42		self.adjust_for_architecture();
43
44	# one pointer is the ISA
45	# then there are 32 bit worth of flags and other data
46	# however, on 64bit systems these are padded to be a full
47	# machine word long, which means we actually have two pointers
48	# worth of data to skip
49	def offset(self):
50		return 2 * self.sys_params.pointer_size
51
52	def length(self):
53		logger = lldb.formatters.Logger.Logger()
54		logger >> "NSConcreteData_SummaryProvider length"
55		size = self.valobj.CreateChildAtOffset("count",
56							self.offset(),
57							self.sys_params.types_cache.NSUInteger)
58		logger >> str(size)
59		logger >> str(size.GetValueAsUnsigned(0))
60		return size.GetValueAsUnsigned(0)
61
62
63class NSDataUnknown_SummaryProvider:
64	def adjust_for_architecture(self):
65		pass
66
67	def __init__(self, valobj, params):
68		logger = lldb.formatters.Logger.Logger()
69		logger >> "NSDataUnknown_SummaryProvider __init__"
70		self.valobj = valobj;
71		self.sys_params = params
72		self.update();
73
74	def update(self):
75		self.adjust_for_architecture();
76
77	def length(self):
78		logger = lldb.formatters.Logger.Logger()
79		logger >> "NSDataUnknown_SummaryProvider length"
80		stream = lldb.SBStream()
81		self.valobj.GetExpressionPath(stream)
82		logger >> stream.GetData()
83		num_children_vo = self.valobj.CreateValueFromExpression("count","(int)[" + stream.GetData() + " length]");
84		logger >> "still in after expression: " + str(num_children_vo)
85		if num_children_vo.IsValid():
86			logger >> "wow - expr output is valid: " + str(num_children_vo.GetValueAsUnsigned())
87			return num_children_vo.GetValueAsUnsigned(0)
88		logger >> "invalid expr output - too bad"
89		return '<variable is not NSData>'
90
91
92def GetSummary_Impl(valobj):
93	global statistics
94	logger = lldb.formatters.Logger.Logger()
95	logger >> "NSData GetSummary_Impl"
96	class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics)
97	if wrapper:
98		logger >> "got a wrapper summary - using it"
99		return wrapper
100
101	name_string = class_data.class_name()
102	logger >> "class name: " + name_string
103	if name_string == 'NSConcreteData' or \
104	   name_string == 'NSConcreteMutableData' or \
105	   name_string == '__NSCFData':
106		wrapper = NSConcreteData_SummaryProvider(valobj, class_data.sys_params)
107		statistics.metric_hit('code_notrun',valobj)
108	else:
109		wrapper = NSDataUnknown_SummaryProvider(valobj, class_data.sys_params)
110		statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
111	return wrapper;
112
113def NSData_SummaryProvider (valobj,dict):
114	logger = lldb.formatters.Logger.Logger()
115	logger >> "NSData_SummaryProvider"
116	provider = GetSummary_Impl(valobj);
117	logger >> "found a summary provider, it is: " + str(provider)
118	if provider != None:
119		try:
120			summary = provider.length();
121		except:
122			summary = None
123		logger >> "got a summary: it is " + str(summary)
124		if summary == None:
125			summary = '<variable is not NSData>'
126		elif isinstance(summary,basestring):
127			pass
128		else:
129			if summary == 1:
130				summary = '1 byte'
131			else:
132				summary = str(summary) + ' bytes'
133		return summary
134	return 'Summary Unavailable'
135
136def NSData_SummaryProvider2 (valobj,dict):
137	logger = lldb.formatters.Logger.Logger()
138	logger >> "NSData_SummaryProvider2"
139	provider = GetSummary_Impl(valobj);
140	logger >> "found a summary provider, it is: " + str(provider)
141	if provider != None:
142		if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
143			return provider.message()
144		try:
145			summary = provider.length();
146		except:
147			summary = None
148		logger >> "got a summary: it is " + str(summary)
149		if summary == None:
150			summary = '<variable is not CFData>'
151		elif isinstance(summary,basestring):
152			pass
153		else:
154			if summary == 1:
155				summary = '@"1 byte"'
156			else:
157				summary = '@"' + str(summary) + ' bytes"'
158		return summary
159	return 'Summary Unavailable'
160
161def __lldb_init_module(debugger,dict):
162	debugger.HandleCommand("type summary add -F NSData.NSData_SummaryProvider NSData")
163	debugger.HandleCommand("type summary add -F NSData.NSData_SummaryProvider2 CFDataRef CFMutableDataRef")
164