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 NS(Mutable)IndexSet
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 # 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
27 class NSIndexSetClass_SummaryProvider
:
28 def adjust_for_architecture(self
):
31 def __init__(self
, valobj
, params
):
32 logger
= lldb
.formatters
.Logger
.Logger()
34 self
.sys_params
= params
35 if not (self
.sys_params
.types_cache
.NSUInteger
):
36 if self
.sys_params
.is_64_bit
:
37 self
.sys_params
.types_cache
.NSUInteger
= (
38 self
.valobj
.GetType().GetBasicType(lldb
.eBasicTypeUnsignedLong
)
40 self
.sys_params
.types_cache
.uint32
= self
.valobj
.GetType().GetBasicType(
41 lldb
.eBasicTypeUnsignedInt
44 self
.sys_params
.types_cache
.NSUInteger
= (
45 self
.valobj
.GetType().GetBasicType(lldb
.eBasicTypeUnsignedInt
)
47 self
.sys_params
.types_cache
.uint32
= self
.valobj
.GetType().GetBasicType(
48 lldb
.eBasicTypeUnsignedInt
50 if not (self
.sys_params
.types_cache
.uint32
):
51 self
.sys_params
.types_cache
.uint32
= self
.valobj
.GetType().GetBasicType(
52 lldb
.eBasicTypeUnsignedInt
57 logger
= lldb
.formatters
.Logger
.Logger()
58 self
.adjust_for_architecture()
60 # NS(Mutable)IndexSet works in one of two modes: when having a compact block of data (e.g. a Range)
61 # the count is stored in the set itself, 3 pointers into it
62 # otherwise, it will store a pointer to an additional data structure (2 pointers into itself) and this
63 # additional structure will contain the count two pointers deep
64 # a bunch of flags allow us to detect an empty set, vs. a one-range set,
65 # vs. a multi-range set
67 logger
= lldb
.formatters
.Logger
.Logger()
68 mode_chooser_vo
= self
.valobj
.CreateChildAtOffset(
70 self
.sys_params
.pointer_size
,
71 self
.sys_params
.types_cache
.uint32
,
73 mode_chooser
= mode_chooser_vo
.GetValueAsUnsigned(0)
74 if self
.sys_params
.is_64_bit
:
75 mode_chooser
= mode_chooser
& 0x00000000FFFFFFFF
77 if mode_chooser
& 0x01 == 1:
80 if mode_chooser
& 0x02 == 2:
86 count_vo
= self
.valobj
.CreateChildAtOffset(
88 3 * self
.sys_params
.pointer_size
,
89 self
.sys_params
.types_cache
.NSUInteger
,
92 count_ptr
= self
.valobj
.CreateChildAtOffset(
94 2 * self
.sys_params
.pointer_size
,
95 self
.sys_params
.types_cache
.NSUInteger
,
97 count_vo
= self
.valobj
.CreateValueFromAddress(
99 count_ptr
.GetValueAsUnsigned() + 2 * self
.sys_params
.pointer_size
,
100 self
.sys_params
.types_cache
.NSUInteger
,
102 return count_vo
.GetValueAsUnsigned(0)
105 class NSIndexSetUnknown_SummaryProvider
:
106 def adjust_for_architecture(self
):
109 def __init__(self
, valobj
, params
):
110 logger
= lldb
.formatters
.Logger
.Logger()
112 self
.sys_params
= params
116 logger
= lldb
.formatters
.Logger
.Logger()
117 self
.adjust_for_architecture()
120 logger
= lldb
.formatters
.Logger
.Logger()
121 stream
= lldb
.SBStream()
122 self
.valobj
.GetExpressionPath(stream
)
123 expr
= "(int)[" + stream
.GetData() + " count]"
124 num_children_vo
= self
.valobj
.CreateValueFromExpression("count", expr
)
125 if num_children_vo
.IsValid():
126 return num_children_vo
.GetValueAsUnsigned(0)
127 return "<variable is not NSIndexSet>"
130 def GetSummary_Impl(valobj
):
131 logger
= lldb
.formatters
.Logger
.Logger()
136 ) = lldb
.runtime
.objc
.objc_runtime
.Utilities
.prepare_class_detection(
142 name_string
= class_data
.class_name()
143 logger
>> "class name is: " + str(name_string
)
145 if name_string
== "NSIndexSet" or name_string
== "NSMutableIndexSet":
146 wrapper
= NSIndexSetClass_SummaryProvider(valobj
, class_data
.sys_params
)
147 statistics
.metric_hit("code_notrun", valobj
)
149 wrapper
= NSIndexSetUnknown_SummaryProvider(valobj
, class_data
.sys_params
)
150 statistics
.metric_hit(
151 "unknown_class", valobj
.GetName() + " seen as " + name_string
156 def NSIndexSet_SummaryProvider(valobj
, dict):
157 logger
= lldb
.formatters
.Logger
.Logger()
158 provider
= GetSummary_Impl(valobj
)
159 if provider
is not None:
161 provider
, lldb
.runtime
.objc
.objc_runtime
.SpecialSituation_Description
163 return provider
.message()
165 summary
= provider
.count()
168 logger
>> "got summary " + str(summary
)
170 summary
= "<variable is not NSIndexSet>"
171 if isinstance(summary
, str):
174 summary
= str(summary
) + (" indexes" if summary
!= 1 else " index")
176 return "Summary Unavailable"
179 def __lldb_init_module(debugger
, dict):
180 debugger
.HandleCommand(
181 "type summary add -F NSIndexSet.NSIndexSet_SummaryProvider NSIndexSet NSMutableIndexSet"