xref: /llvm-project/lldb/examples/summaries/cocoa/CFBinaryHeap.py (revision 2238dcc39358353cac21df75c3c3286ab20b8f53)
1"""
2LLDB AppKit formatters
3
4Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5See https://llvm.org/LICENSE.txt for license information.
6SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7"""
8# example summary provider for CFBinaryHeap
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 length for an CFBinaryHeap, so they need not
24# obey the interface specification for synthetic children providers
25
26
27class CFBinaryHeapRef_SummaryProvider:
28    def adjust_for_architecture(self):
29        pass
30
31    def __init__(self, valobj, params):
32        logger = lldb.formatters.Logger.Logger()
33        self.valobj = valobj
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)
39                )
40            else:
41                self.sys_params.types_cache.NSUInteger = (
42                    self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
43                )
44        self.update()
45
46    def update(self):
47        logger = lldb.formatters.Logger.Logger()
48        self.adjust_for_architecture()
49
50    # 8 bytes on i386
51    # 16 bytes on x64
52    # most probably 2 pointers
53    def offset(self):
54        logger = lldb.formatters.Logger.Logger()
55        return 2 * self.sys_params.pointer_size
56
57    def length(self):
58        logger = lldb.formatters.Logger.Logger()
59        size = self.valobj.CreateChildAtOffset(
60            "count", self.offset(), self.sys_params.types_cache.NSUInteger
61        )
62        return size.GetValueAsUnsigned(0)
63
64
65class CFBinaryHeapUnknown_SummaryProvider:
66    def adjust_for_architecture(self):
67        pass
68
69    def __init__(self, valobj, params):
70        logger = lldb.formatters.Logger.Logger()
71        self.valobj = valobj
72        self.sys_params = params
73        self.update()
74
75    def update(self):
76        logger = lldb.formatters.Logger.Logger()
77        self.adjust_for_architecture()
78
79    def length(self):
80        logger = lldb.formatters.Logger.Logger()
81        stream = lldb.SBStream()
82        self.valobj.GetExpressionPath(stream)
83        num_children_vo = self.valobj.CreateValueFromExpression(
84            "count", "(int)CFBinaryHeapGetCount(" + stream.GetData() + " )"
85        )
86        if num_children_vo.IsValid():
87            return num_children_vo.GetValueAsUnsigned(0)
88        return "<variable is not CFBinaryHeap>"
89
90
91def GetSummary_Impl(valobj):
92    logger = lldb.formatters.Logger.Logger()
93    global statistics
94    (
95        class_data,
96        wrapper,
97    ) = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
98        valobj, statistics
99    )
100    if wrapper:
101        return wrapper
102
103    name_string = class_data.class_name()
104    actual_name = class_data.class_name()
105
106    logger >> "name string got was " + str(name_string) + " but actual name is " + str(
107        actual_name
108    )
109
110    if class_data.is_cftype():
111        # CFBinaryHeap does not expose an actual NSWrapper type, so we have to check that this is
112        # an NSCFType and then check we are a pointer-to CFBinaryHeap
113        valobj_type = valobj.GetType()
114        if valobj_type.IsValid() and valobj_type.IsPointerType():
115            valobj_type = valobj_type.GetPointeeType()
116            if valobj_type.IsValid():
117                actual_name = valobj_type.GetName()
118        if actual_name == "__CFBinaryHeap":
119            wrapper = CFBinaryHeapRef_SummaryProvider(valobj, class_data.sys_params)
120            statistics.metric_hit("code_notrun", valobj)
121            return wrapper
122    wrapper = CFBinaryHeapUnknown_SummaryProvider(valobj, class_data.sys_params)
123    statistics.metric_hit("unknown_class", valobj.GetName() + " seen as " + name_string)
124    return wrapper
125
126
127def CFBinaryHeap_SummaryProvider(valobj, dict):
128    logger = lldb.formatters.Logger.Logger()
129    provider = GetSummary_Impl(valobj)
130    if provider is not None:
131        if isinstance(
132            provider, lldb.runtime.objc.objc_runtime.SpecialSituation_Description
133        ):
134            return provider.message()
135        try:
136            summary = provider.length()
137        except:
138            summary = None
139        logger >> "summary got from provider: " + str(summary)
140        # for some reason, one needs to clear some bits for the count
141        # to be correct when using CF(Mutable)BagRef on x64
142        # the bit mask was derived through experimentation
143        # (if counts start looking weird, then most probably
144        #  the mask needs to be changed)
145        if summary is None:
146            summary = "<variable is not CFBinaryHeap>"
147        elif isinstance(summary, str):
148            pass
149        else:
150            if provider.sys_params.is_64_bit:
151                summary = summary & ~0x1FFF000000000000
152            if summary == 1:
153                return '@"1 item"'
154            else:
155                summary = '@"' + str(summary) + ' items"'
156        return summary
157    return "Summary Unavailable"
158
159
160def __lldb_init_module(debugger, dict):
161    debugger.HandleCommand(
162        "type summary add -F CFBinaryHeap.CFBinaryHeap_SummaryProvider CFBinaryHeapRef"
163    )
164