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# summary provider for CF(Mutable)BitVector
9import lldb
10import ctypes
11import lldb.runtime.objc.objc_runtime
12import lldb.formatters.metrics
13import lldb.formatters.Logger
14
15# first define some utility functions
16def byte_index(abs_pos):
17	logger = lldb.formatters.Logger.Logger()
18	return abs_pos/8
19
20def bit_index(abs_pos):
21	logger = lldb.formatters.Logger.Logger()
22	return abs_pos & 7
23
24def get_bit(byte,index):
25	logger = lldb.formatters.Logger.Logger()
26	if index < 0 or index > 7:
27		return None
28	return (byte >> (7-index)) & 1
29
30def grab_array_item_data(pointer,index):
31	logger = lldb.formatters.Logger.Logger()
32	return pointer.GetPointeeData(index,1)
33
34statistics = lldb.formatters.metrics.Metrics()
35statistics.add_metric('invalid_isa')
36statistics.add_metric('invalid_pointer')
37statistics.add_metric('unknown_class')
38statistics.add_metric('code_notrun')
39
40# despite the similary to synthetic children providers, these classes are not
41# trying to provide anything but a summary for a CF*BitVector, so they need not
42# obey the interface specification for synthetic children providers
43class CFBitVectorKnown_SummaryProvider:
44	def adjust_for_architecture(self):
45		logger = lldb.formatters.Logger.Logger()
46		self.uiint_size = self.sys_params.types_cache.NSUInteger.GetByteSize()
47		pass
48
49	def __init__(self, valobj, params):
50		logger = lldb.formatters.Logger.Logger()
51		self.valobj = valobj;
52		self.sys_params = params
53		if not(self.sys_params.types_cache.NSUInteger):
54			if self.sys_params.is_64_bit:
55				self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
56			else:
57				self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
58		if not(self.sys_params.types_cache.charptr):
59			self.sys_params.types_cache.charptr = self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar).GetPointerType()
60		self.update();
61
62	def update(self):
63		logger = lldb.formatters.Logger.Logger()
64		self.adjust_for_architecture();
65
66	# we skip the CFRuntimeBase
67	# then the next CFIndex is the count
68	# then we skip another CFIndex and then we get at a byte array
69	# that wraps the individual bits
70
71	def contents(self):
72		logger = lldb.formatters.Logger.Logger()
73		count_vo = self.valobj.CreateChildAtOffset("count",self.sys_params.cfruntime_size,
74													self.sys_params.types_cache.NSUInteger)
75		count = count_vo.GetValueAsUnsigned(0)
76		if count == 0:
77			return '(empty)'
78
79		array_vo = self.valobj.CreateChildAtOffset("data",
80													self.sys_params.cfruntime_size+2*self.uiint_size,
81													self.sys_params.types_cache.charptr)
82
83		data_list = []
84		cur_byte_pos = None
85		for i in range(0,count):
86			if cur_byte_pos == None:
87				cur_byte_pos = byte_index(i)
88				cur_byte = grab_array_item_data(array_vo,cur_byte_pos)
89				cur_byte_val = cur_byte.uint8[0]
90			else:
91				byte_pos = byte_index(i)
92				# do not fetch the pointee data every single time through
93				if byte_pos != cur_byte_pos:
94					cur_byte_pos = byte_pos
95					cur_byte = grab_array_item_data(array_vo,cur_byte_pos)
96					cur_byte_val = cur_byte.uint8[0]
97			bit = get_bit(cur_byte_val,bit_index(i))
98			if (i % 4) == 0:
99				data_list.append(' ')
100			if bit == 1:
101				data_list.append('1')
102			else:
103				data_list.append('0')
104		return ''.join(data_list)
105
106
107class CFBitVectorUnknown_SummaryProvider:
108	def adjust_for_architecture(self):
109		pass
110
111	def __init__(self, valobj, params):
112		logger = lldb.formatters.Logger.Logger()
113		self.valobj = valobj;
114		self.sys_params = params
115		self.update();
116
117	def update(self):
118		logger = lldb.formatters.Logger.Logger()
119		self.adjust_for_architecture();
120
121	def contents(self):
122		logger = lldb.formatters.Logger.Logger()
123		return '<unable to summarize this CFBitVector>'
124
125
126def GetSummary_Impl(valobj):
127	logger = lldb.formatters.Logger.Logger()
128	global statistics
129	class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics)
130	if wrapper:
131		return wrapper
132
133	name_string = class_data.class_name()
134	actual_name = name_string
135
136	logger >> "name string got was " + str(name_string) + " but actual name is " + str(actual_name)
137
138	if class_data.is_cftype():
139		# CFBitVectorRef does not expose an actual NSWrapper type, so we have to check that this is
140		# an NSCFType and then check we are a pointer-to CFBitVectorRef
141		valobj_type = valobj.GetType()
142		if valobj_type.IsValid() and valobj_type.IsPointerType():
143			valobj_type = valobj_type.GetPointeeType()
144			if valobj_type.IsValid():
145				actual_name = valobj_type.GetName()
146		if actual_name == '__CFBitVector' or actual_name == '__CFMutableBitVector':
147			wrapper = CFBitVectorKnown_SummaryProvider(valobj, class_data.sys_params)
148			statistics.metric_hit('code_notrun',valobj)
149		else:
150			wrapper = CFBitVectorUnknown_SummaryProvider(valobj, class_data.sys_params)
151			print actual_name
152	else:
153		wrapper = CFBitVectorUnknown_SummaryProvider(valobj, class_data.sys_params)
154		print name_string
155		statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
156	return wrapper;
157
158def CFBitVector_SummaryProvider (valobj,dict):
159	logger = lldb.formatters.Logger.Logger()
160	provider = GetSummary_Impl(valobj);
161	if provider != None:
162		if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
163			return provider.message()
164		try:
165			summary = provider.contents();
166		except:
167			summary = None
168		logger >> "summary got from provider: " + str(summary)
169		if summary == None or summary == '':
170			summary = '<variable is not CFBitVector>'
171		return summary
172	return 'Summary Unavailable'
173
174def __lldb_init_module(debugger,dict):
175	debugger.HandleCommand("type summary add -F CFBitVector.CFBitVector_SummaryProvider CFBitVectorRef CFMutableBitVectorRef")
176