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 NS(Mutable)IndexSet
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 count of values for an NSIndexSet, so they need not
24# obey the interface specification for synthetic children providers
25class NSIndexSetClass_SummaryProvider:
26	def adjust_for_architecture(self):
27		pass
28
29	def __init__(self, valobj, params):
30		logger = lldb.formatters.Logger.Logger()
31		self.valobj = valobj;
32		self.sys_params = params
33		if not(self.sys_params.types_cache.NSUInteger):
34			if self.sys_params.is_64_bit:
35				self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
36				self.sys_params.types_cache.uint32 = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
37			else:
38				self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
39				self.sys_params.types_cache.uint32 = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
40		if not(self.sys_params.types_cache.uint32):
41			self.sys_params.types_cache.uint32 = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
42		self.update();
43
44	def update(self):
45		logger = lldb.formatters.Logger.Logger()
46		self.adjust_for_architecture();
47
48	# NS(Mutable)IndexSet works in one of two modes: when having a compact block of data (e.g. a Range)
49	# the count is stored in the set itself, 3 pointers into it
50	# otherwise, it will store a pointer to an additional data structure (2 pointers into itself) and this
51	# additional structure will contain the count two pointers deep
52	# a bunch of flags allow us to detect an empty set, vs. a one-range set, vs. a multi-range set
53	def count(self):
54		logger = lldb.formatters.Logger.Logger()
55		mode_chooser_vo = self.valobj.CreateChildAtOffset("mode_chooser",
56							self.sys_params.pointer_size,
57							self.sys_params.types_cache.uint32)
58		mode_chooser =  mode_chooser_vo.GetValueAsUnsigned(0)
59		if self.sys_params.is_64_bit:
60			mode_chooser = mode_chooser & 0x00000000FFFFFFFF
61		# empty set
62		if mode_chooser & 0x01 == 1:
63			return 0
64		# single range
65		if mode_chooser & 0x02 == 2:
66			mode = 1
67		# multi range
68		else:
69			mode = 2
70		if mode == 1:
71			count_vo = self.valobj.CreateChildAtOffset("count",
72								3*self.sys_params.pointer_size,
73								self.sys_params.types_cache.NSUInteger)
74		else:
75			count_ptr = self.valobj.CreateChildAtOffset("count_ptr",
76								2*self.sys_params.pointer_size,
77								self.sys_params.types_cache.NSUInteger)
78			count_vo = self.valobj.CreateValueFromAddress("count",
79								count_ptr.GetValueAsUnsigned()+2*self.sys_params.pointer_size,
80								self.sys_params.types_cache.NSUInteger)
81		return count_vo.GetValueAsUnsigned(0)
82
83
84class NSIndexSetUnknown_SummaryProvider:
85	def adjust_for_architecture(self):
86		pass
87
88	def __init__(self, valobj, params):
89		logger = lldb.formatters.Logger.Logger()
90		self.valobj = valobj;
91		self.sys_params = params
92		self.update();
93
94	def update(self):
95		logger = lldb.formatters.Logger.Logger()
96		self.adjust_for_architecture();
97
98	def count(self):
99		logger = lldb.formatters.Logger.Logger()
100		stream = lldb.SBStream()
101		self.valobj.GetExpressionPath(stream)
102		expr = "(int)[" + stream.GetData() + " count]"
103		num_children_vo = self.valobj.CreateValueFromExpression("count",expr)
104		if num_children_vo.IsValid():
105			return num_children_vo.GetValueAsUnsigned(0)
106		return '<variable is not NSIndexSet>'
107
108
109def GetSummary_Impl(valobj):
110	logger = lldb.formatters.Logger.Logger()
111	global statistics
112	class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics)
113	if wrapper:
114		return wrapper
115
116	name_string = class_data.class_name()
117	logger >> "class name is: " + str(name_string)
118
119	if name_string == 'NSIndexSet' or name_string == 'NSMutableIndexSet':
120		wrapper = NSIndexSetClass_SummaryProvider(valobj, class_data.sys_params)
121		statistics.metric_hit('code_notrun',valobj)
122	else:
123		wrapper = NSIndexSetUnknown_SummaryProvider(valobj, class_data.sys_params)
124		statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
125	return wrapper;
126
127
128def NSIndexSet_SummaryProvider (valobj,dict):
129	logger = lldb.formatters.Logger.Logger()
130	provider = GetSummary_Impl(valobj);
131	if provider != None:
132		if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
133			return provider.message()
134		try:
135			summary = provider.count();
136		except:
137			summary = None
138		logger >> "got summary " + str(summary)
139		if summary == None:
140			summary = '<variable is not NSIndexSet>'
141		if isinstance(summary, basestring):
142			return summary
143		else:
144			summary = str(summary) + (' indexes' if summary != 1 else ' index')
145		return summary
146	return 'Summary Unavailable'
147
148
149def __lldb_init_module(debugger,dict):
150	debugger.HandleCommand("type summary add -F NSIndexSet.NSIndexSet_SummaryProvider NSIndexSet NSMutableIndexSet")
151