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 NSMachPort
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
16try:
17    basestring
18except NameError:
19    basestring =str
20
21statistics = lldb.formatters.metrics.Metrics()
22statistics.add_metric('invalid_isa')
23statistics.add_metric('invalid_pointer')
24statistics.add_metric('unknown_class')
25statistics.add_metric('code_notrun')
26
27# despite the similary to synthetic children providers, these classes are not
28# trying to provide anything but the port number of an NSMachPort, so they need not
29# obey the interface specification for synthetic children providers
30
31
32class NSMachPortKnown_SummaryProvider:
33
34    def adjust_for_architecture(self):
35        pass
36
37    def __init__(self, valobj, params):
38        logger = lldb.formatters.Logger.Logger()
39        self.valobj = valobj
40        self.sys_params = params
41        if not(self.sys_params.types_cache.NSUInteger):
42            if self.sys_params.is_64_bit:
43                self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
44                ).GetBasicType(lldb.eBasicTypeUnsignedLong)
45            else:
46                self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
47                ).GetBasicType(lldb.eBasicTypeUnsignedInt)
48        self.update()
49
50    def update(self):
51        logger = lldb.formatters.Logger.Logger()
52        self.adjust_for_architecture()
53
54    # one pointer is the ISA
55    # then we have one other internal pointer, plus
56    # 4 bytes worth of flags. hence, these values
57    def offset(self):
58        logger = lldb.formatters.Logger.Logger()
59        if self.sys_params.is_64_bit:
60            return 20
61        else:
62            return 12
63
64    def port(self):
65        logger = lldb.formatters.Logger.Logger()
66        vport = self.valobj.CreateChildAtOffset(
67            "port", self.offset(), self.sys_params.types_cache.NSUInteger)
68        return vport.GetValueAsUnsigned(0)
69
70
71class NSMachPortUnknown_SummaryProvider:
72
73    def adjust_for_architecture(self):
74        pass
75
76    def __init__(self, valobj, params):
77        logger = lldb.formatters.Logger.Logger()
78        self.valobj = valobj
79        self.sys_params = params
80        self.update()
81
82    def update(self):
83        logger = lldb.formatters.Logger.Logger()
84        self.adjust_for_architecture()
85
86    def port(self):
87        logger = lldb.formatters.Logger.Logger()
88        stream = lldb.SBStream()
89        self.valobj.GetExpressionPath(stream)
90        num_children_vo = self.valobj.CreateValueFromExpression(
91            "port", "(int)[" + stream.GetData() + " machPort]")
92        if num_children_vo.IsValid():
93            return num_children_vo.GetValueAsUnsigned(0)
94        return '<variable is not NSMachPort>'
95
96
97def GetSummary_Impl(valobj):
98    logger = lldb.formatters.Logger.Logger()
99    global statistics
100    class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
101        valobj, statistics)
102    if wrapper:
103        return wrapper
104
105    name_string = class_data.class_name()
106    logger >> "class name is: " + str(name_string)
107
108    if name_string == 'NSMachPort':
109        wrapper = NSMachPortKnown_SummaryProvider(
110            valobj, class_data.sys_params)
111        statistics.metric_hit('code_notrun', valobj)
112    else:
113        wrapper = NSMachPortUnknown_SummaryProvider(
114            valobj, class_data.sys_params)
115        statistics.metric_hit(
116            'unknown_class',
117            valobj.GetName() +
118            " seen as " +
119            name_string)
120    return wrapper
121
122
123def NSMachPort_SummaryProvider(valobj, dict):
124    logger = lldb.formatters.Logger.Logger()
125    provider = GetSummary_Impl(valobj)
126    if provider is not None:
127        if isinstance(
128                provider,
129                lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
130            return provider.message()
131        try:
132            summary = provider.port()
133        except:
134            summary = None
135        logger >> "got summary " + str(summary)
136        if summary is None:
137            summary = '<variable is not NSMachPort>'
138        if isinstance(summary, basestring):
139            return summay
140        return 'mach port: ' + str(summary)
141    return 'Summary Unavailable'
142
143
144def __lldb_init_module(debugger, dict):
145    debugger.HandleCommand(
146        "type summary add -F NSMachPort.NSMachPort_SummaryProvider NSMachPort")
147