4 Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 See https://llvm.org/LICENSE.txt for license information.
6 SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 # example summary provider for NSArray
9 # the real summary is now C++ code built into LLDB
12 import lldb
.runtime
.objc
.objc_runtime
13 import lldb
.formatters
.metrics
14 import lldb
.formatters
.Logger
16 statistics
= lldb
.formatters
.metrics
.Metrics()
17 statistics
.add_metric("invalid_isa")
18 statistics
.add_metric("invalid_pointer")
19 statistics
.add_metric("unknown_class")
20 statistics
.add_metric("code_notrun")
22 # much less functional than the other two cases below
23 # just runs code to get to the count and then returns
27 class NSArrayKVC_SynthProvider
:
28 def adjust_for_architecture(self
):
31 def __init__(self
, valobj
, dict, params
):
32 logger
= lldb
.formatters
.Logger
.Logger()
37 logger
= lldb
.formatters
.Logger
.Logger()
38 self
.adjust_for_architecture()
40 def num_children(self
):
41 logger
= lldb
.formatters
.Logger
.Logger()
42 stream
= lldb
.SBStream()
43 self
.valobj
.GetExpressionPath(stream
)
44 num_children_vo
= self
.valobj
.CreateValueFromExpression(
45 "count", "(int)[" + stream
.GetData() + " count]"
47 if num_children_vo
.IsValid():
48 return num_children_vo
.GetValueAsUnsigned(0)
49 return "<variable is not NSArray>"
52 # much less functional than the other two cases below
53 # just runs code to get to the count and then returns
57 class NSArrayCF_SynthProvider
:
58 def adjust_for_architecture(self
):
61 def __init__(self
, valobj
, dict, params
):
62 logger
= lldb
.formatters
.Logger
.Logger()
64 self
.sys_params
= params
65 if not (self
.sys_params
.types_cache
.ulong
):
66 self
.sys_params
.types_cache
.ulong
= self
.valobj
.GetType().GetBasicType(
67 lldb
.eBasicTypeUnsignedLong
72 logger
= lldb
.formatters
.Logger
.Logger()
73 self
.adjust_for_architecture()
75 def num_children(self
):
76 logger
= lldb
.formatters
.Logger
.Logger()
77 num_children_vo
= self
.valobj
.CreateChildAtOffset(
78 "count", self
.sys_params
.cfruntime_size
, self
.sys_params
.types_cache
.ulong
80 return num_children_vo
.GetValueAsUnsigned(0)
83 class NSArrayI_SynthProvider
:
84 def adjust_for_architecture(self
):
87 def __init__(self
, valobj
, dict, params
):
88 logger
= lldb
.formatters
.Logger
.Logger()
90 self
.sys_params
= params
91 if not (self
.sys_params
.types_cache
.long):
92 self
.sys_params
.types_cache
.long = self
.valobj
.GetType().GetBasicType(
98 logger
= lldb
.formatters
.Logger
.Logger()
99 self
.adjust_for_architecture()
101 # skip the isa pointer and get at the size
102 def num_children(self
):
103 logger
= lldb
.formatters
.Logger
.Logger()
104 count
= self
.valobj
.CreateChildAtOffset(
105 "count", self
.sys_params
.pointer_size
, self
.sys_params
.types_cache
.long
107 return count
.GetValueAsUnsigned(0)
110 class NSArrayM_SynthProvider
:
111 def adjust_for_architecture(self
):
114 def __init__(self
, valobj
, dict, params
):
115 logger
= lldb
.formatters
.Logger
.Logger()
117 self
.sys_params
= params
118 if not (self
.sys_params
.types_cache
.long):
119 self
.sys_params
.types_cache
.long = self
.valobj
.GetType().GetBasicType(
125 logger
= lldb
.formatters
.Logger
.Logger()
126 self
.adjust_for_architecture()
128 # skip the isa pointer and get at the size
129 def num_children(self
):
130 logger
= lldb
.formatters
.Logger
.Logger()
131 count
= self
.valobj
.CreateChildAtOffset(
132 "count", self
.sys_params
.pointer_size
, self
.sys_params
.types_cache
.long
134 return count
.GetValueAsUnsigned(0)
137 # this is the actual synth provider, but is just a wrapper that checks
138 # whether valobj is an instance of __NSArrayI or __NSArrayM and sets up an
139 # appropriate backend layer to do the computations
142 class NSArray_SynthProvider
:
143 def adjust_for_architecture(self
):
146 def __init__(self
, valobj
, dict):
147 logger
= lldb
.formatters
.Logger
.Logger()
149 self
.adjust_for_architecture()
151 self
.wrapper
= self
.make_wrapper()
152 self
.invalid
= self
.wrapper
is None
154 def num_children(self
):
155 logger
= lldb
.formatters
.Logger
.Logger()
156 if self
.wrapper
is None:
158 return self
.wrapper
.num_children()
161 logger
= lldb
.formatters
.Logger
.Logger()
162 if self
.wrapper
is None:
164 self
.wrapper
.update()
166 # this code acts as our defense against NULL and uninitialized
167 # NSArray pointers, which makes it much longer than it would be otherwise
168 def make_wrapper(self
):
169 logger
= lldb
.formatters
.Logger
.Logger()
170 if self
.valobj
.GetValueAsUnsigned() == 0:
172 return lldb
.runtime
.objc
.objc_runtime
.InvalidPointer_Description(True)
178 ) = lldb
.runtime
.objc
.objc_runtime
.Utilities
.prepare_class_detection(
179 self
.valobj
, statistics
185 name_string
= class_data
.class_name()
187 logger
>> "Class name is " + str(name_string
)
189 if name_string
== "__NSArrayI":
190 wrapper
= NSArrayI_SynthProvider(self
.valobj
, dict, class_data
.sys_params
)
191 statistics
.metric_hit("code_notrun", self
.valobj
.GetName())
192 elif name_string
== "__NSArrayM":
193 wrapper
= NSArrayM_SynthProvider(self
.valobj
, dict, class_data
.sys_params
)
194 statistics
.metric_hit("code_notrun", self
.valobj
.GetName())
195 elif name_string
== "__NSCFArray":
196 wrapper
= NSArrayCF_SynthProvider(self
.valobj
, dict, class_data
.sys_params
)
197 statistics
.metric_hit("code_notrun", self
.valobj
.GetName())
199 wrapper
= NSArrayKVC_SynthProvider(self
.valobj
, dict, class_data
.sys_params
)
200 statistics
.metric_hit(
201 "unknown_class", str(self
.valobj
.GetName()) + " seen as " + name_string
206 def CFArray_SummaryProvider(valobj
, dict):
207 logger
= lldb
.formatters
.Logger
.Logger()
208 provider
= NSArray_SynthProvider(valobj
, dict)
209 if not provider
.invalid
:
211 return provider
.wrapper
.message()
213 summary
= int(provider
.num_children())
216 logger
>> "provider gave me " + str(summary
)
218 summary
= "<variable is not NSArray>"
219 elif isinstance(summary
, str):
222 # we format it like it were a CFString to make it look the same as
223 # the summary from Xcode
225 '@"' + str(summary
) + (" objects" if summary
!= 1 else " object") + '"'
228 return "Summary Unavailable"
231 def __lldb_init_module(debugger
, dict):
232 debugger
.HandleCommand(
233 "type summary add -F CFArray.CFArray_SummaryProvider NSArray CFArrayRef CFMutableArrayRef"