xref: /llvm-project/lldb/examples/summaries/cocoa/NSNotification.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 NSNotification
9# the real summary is now C++ code built into LLDB
10import lldb.runtime.objc.objc_runtime
11import lldb.formatters.metrics
12import CFString
13import lldb
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
23class NSConcreteNotification_SummaryProvider:
24    def adjust_for_architecture(self):
25        pass
26
27    def __init__(self, valobj, params):
28        logger = lldb.formatters.Logger.Logger()
29        self.valobj = valobj
30        self.sys_params = params
31        if not (self.sys_params.types_cache.id):
32            self.sys_params.types_cache.id = self.valobj.GetType().GetBasicType(
33                lldb.eBasicTypeObjCID
34            )
35        self.update()
36
37    def update(self):
38        logger = lldb.formatters.Logger.Logger()
39        self.adjust_for_architecture()
40
41    # skip the ISA and go to the name pointer
42    def offset(self):
43        logger = lldb.formatters.Logger.Logger()
44        return self.sys_params.pointer_size
45
46    def name(self):
47        logger = lldb.formatters.Logger.Logger()
48        string_ptr = self.valobj.CreateChildAtOffset(
49            "name", self.offset(), self.sys_params.types_cache.id
50        )
51        return CFString.CFString_SummaryProvider(string_ptr, None)
52
53
54class NSNotificationUnknown_SummaryProvider:
55    def adjust_for_architecture(self):
56        pass
57
58    def __init__(self, valobj, params):
59        logger = lldb.formatters.Logger.Logger()
60        self.valobj = valobj
61        self.sys_params = params
62        self.update()
63
64    def update(self):
65        logger = lldb.formatters.Logger.Logger()
66        self.adjust_for_architecture()
67
68    def name(self):
69        logger = lldb.formatters.Logger.Logger()
70        stream = lldb.SBStream()
71        self.valobj.GetExpressionPath(stream)
72        name_vo = self.valobj.CreateValueFromExpression(
73            "name", "(NSString*)[" + stream.GetData() + " name]"
74        )
75        if name_vo.IsValid():
76            return CFString.CFString_SummaryProvider(name_vo, None)
77        return "<variable is not NSNotification>"
78
79
80def GetSummary_Impl(valobj):
81    logger = lldb.formatters.Logger.Logger()
82    global statistics
83    (
84        class_data,
85        wrapper,
86    ) = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
87        valobj, statistics
88    )
89    if wrapper:
90        return wrapper
91
92    name_string = class_data.class_name()
93    logger >> "class name is: " + str(name_string)
94
95    if name_string == "NSConcreteNotification":
96        wrapper = NSConcreteNotification_SummaryProvider(valobj, class_data.sys_params)
97        statistics.metric_hit("code_notrun", valobj)
98    else:
99        wrapper = NSNotificationUnknown_SummaryProvider(valobj, class_data.sys_params)
100        statistics.metric_hit(
101            "unknown_class", valobj.GetName() + " seen as " + name_string
102        )
103    return wrapper
104
105
106def NSNotification_SummaryProvider(valobj, dict):
107    logger = lldb.formatters.Logger.Logger()
108    provider = GetSummary_Impl(valobj)
109    if provider is not None:
110        if isinstance(
111            provider, lldb.runtime.objc.objc_runtime.SpecialSituation_Description
112        ):
113            return provider.message()
114        try:
115            summary = provider.name()
116        except:
117            summary = None
118        logger >> "got summary " + str(summary)
119        if summary is None:
120            summary = "<variable is not NSNotification>"
121        return str(summary)
122    return "Summary Unavailable"
123
124
125def __lldb_init_module(debugger, dict):
126    debugger.HandleCommand(
127        "type summary add -F NSNotification.NSNotification_SummaryProvider NSNotification"
128    )
129