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
9 # summary provider for CF(Mutable)BitVector
12 import lldb
.runtime
.objc
.objc_runtime
13 import lldb
.formatters
.metrics
14 import lldb
.formatters
.Logger
16 # first define some utility functions
19 def byte_index(abs_pos
):
20 logger
= lldb
.formatters
.Logger
.Logger()
24 def bit_index(abs_pos
):
25 logger
= lldb
.formatters
.Logger
.Logger()
29 def get_bit(byte
, index
):
30 logger
= lldb
.formatters
.Logger
.Logger()
31 if index
< 0 or index
> 7:
33 return (byte
>> (7 - index
)) & 1
36 def grab_array_item_data(pointer
, index
):
37 logger
= lldb
.formatters
.Logger
.Logger()
38 return pointer
.GetPointeeData(index
, 1)
41 statistics
= lldb
.formatters
.metrics
.Metrics()
42 statistics
.add_metric("invalid_isa")
43 statistics
.add_metric("invalid_pointer")
44 statistics
.add_metric("unknown_class")
45 statistics
.add_metric("code_notrun")
47 # despite the similary to synthetic children providers, these classes are not
48 # trying to provide anything but a summary for a CF*BitVector, so they need not
49 # obey the interface specification for synthetic children providers
52 class CFBitVectorKnown_SummaryProvider
:
53 def adjust_for_architecture(self
):
54 logger
= lldb
.formatters
.Logger
.Logger()
55 self
.uiint_size
= self
.sys_params
.types_cache
.NSUInteger
.GetByteSize()
58 def __init__(self
, valobj
, params
):
59 logger
= lldb
.formatters
.Logger
.Logger()
61 self
.sys_params
= params
62 if not (self
.sys_params
.types_cache
.NSUInteger
):
63 if self
.sys_params
.is_64_bit
:
64 self
.sys_params
.types_cache
.NSUInteger
= (
65 self
.valobj
.GetType().GetBasicType(lldb
.eBasicTypeUnsignedLong
)
68 self
.sys_params
.types_cache
.NSUInteger
= (
69 self
.valobj
.GetType().GetBasicType(lldb
.eBasicTypeUnsignedInt
)
71 if not (self
.sys_params
.types_cache
.charptr
):
72 self
.sys_params
.types_cache
.charptr
= (
73 self
.valobj
.GetType().GetBasicType(lldb
.eBasicTypeChar
).GetPointerType()
78 logger
= lldb
.formatters
.Logger
.Logger()
79 self
.adjust_for_architecture()
81 # we skip the CFRuntimeBase
82 # then the next CFIndex is the count
83 # then we skip another CFIndex and then we get at a byte array
84 # that wraps the individual bits
87 logger
= lldb
.formatters
.Logger
.Logger()
88 count_vo
= self
.valobj
.CreateChildAtOffset(
90 self
.sys_params
.cfruntime_size
,
91 self
.sys_params
.types_cache
.NSUInteger
,
93 count
= count_vo
.GetValueAsUnsigned(0)
97 array_vo
= self
.valobj
.CreateChildAtOffset(
99 self
.sys_params
.cfruntime_size
+ 2 * self
.uiint_size
,
100 self
.sys_params
.types_cache
.charptr
,
105 for i
in range(0, count
):
106 if cur_byte_pos
is None:
107 cur_byte_pos
= byte_index(i
)
108 cur_byte
= grab_array_item_data(array_vo
, cur_byte_pos
)
109 cur_byte_val
= cur_byte
.uint8
[0]
111 byte_pos
= byte_index(i
)
112 # do not fetch the pointee data every single time through
113 if byte_pos
!= cur_byte_pos
:
114 cur_byte_pos
= byte_pos
115 cur_byte
= grab_array_item_data(array_vo
, cur_byte_pos
)
116 cur_byte_val
= cur_byte
.uint8
[0]
117 bit
= get_bit(cur_byte_val
, bit_index(i
))
119 data_list
.append(" ")
121 data_list
.append("1")
123 data_list
.append("0")
124 return "".join(data_list
)
127 class CFBitVectorUnknown_SummaryProvider
:
128 def adjust_for_architecture(self
):
131 def __init__(self
, valobj
, params
):
132 logger
= lldb
.formatters
.Logger
.Logger()
134 self
.sys_params
= params
138 logger
= lldb
.formatters
.Logger
.Logger()
139 self
.adjust_for_architecture()
142 logger
= lldb
.formatters
.Logger
.Logger()
143 return "<unable to summarize this CFBitVector>"
146 def GetSummary_Impl(valobj
):
147 logger
= lldb
.formatters
.Logger
.Logger()
152 ) = lldb
.runtime
.objc
.objc_runtime
.Utilities
.prepare_class_detection(
158 name_string
= class_data
.class_name()
159 actual_name
= name_string
161 logger
>> "name string got was " + str(name_string
) + " but actual name is " + str(
165 if class_data
.is_cftype():
166 # CFBitVectorRef does not expose an actual NSWrapper type, so we have to check that this is
167 # an NSCFType and then check we are a pointer-to CFBitVectorRef
168 valobj_type
= valobj
.GetType()
169 if valobj_type
.IsValid() and valobj_type
.IsPointerType():
170 valobj_type
= valobj_type
.GetPointeeType()
171 if valobj_type
.IsValid():
172 actual_name
= valobj_type
.GetName()
173 if actual_name
== "__CFBitVector" or actual_name
== "__CFMutableBitVector":
174 wrapper
= CFBitVectorKnown_SummaryProvider(valobj
, class_data
.sys_params
)
175 statistics
.metric_hit("code_notrun", valobj
)
177 wrapper
= CFBitVectorUnknown_SummaryProvider(valobj
, class_data
.sys_params
)
180 wrapper
= CFBitVectorUnknown_SummaryProvider(valobj
, class_data
.sys_params
)
182 statistics
.metric_hit(
183 "unknown_class", valobj
.GetName() + " seen as " + name_string
188 def CFBitVector_SummaryProvider(valobj
, dict):
189 logger
= lldb
.formatters
.Logger
.Logger()
190 provider
= GetSummary_Impl(valobj
)
191 if provider
is not None:
193 provider
, lldb
.runtime
.objc
.objc_runtime
.SpecialSituation_Description
195 return provider
.message()
197 summary
= provider
.contents()
200 logger
>> "summary got from provider: " + str(summary
)
201 if summary
is None or summary
== "":
202 summary
= "<variable is not CFBitVector>"
204 return "Summary Unavailable"
207 def __lldb_init_module(debugger
, dict):
208 debugger
.HandleCommand(
209 "type summary add -F CFBitVector.CFBitVector_SummaryProvider CFBitVectorRef CFMutableBitVectorRef"