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