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# summary provider for class NSException
9import lldb.runtime.objc.objc_runtime
10import lldb.formatters.metrics
11import CFString
12import lldb
13import lldb.formatters.Logger
14
15statistics = lldb.formatters.metrics.Metrics()
16statistics.add_metric('invalid_isa')
17statistics.add_metric('invalid_pointer')
18statistics.add_metric('unknown_class')
19statistics.add_metric('code_notrun')
20
21
22class NSKnownException_SummaryProvider:
23
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(
33            ).GetBasicType(lldb.eBasicTypeObjCID)
34        self.update()
35
36    def update(self):
37        logger = lldb.formatters.Logger.Logger()
38        self.adjust_for_architecture()
39
40    def offset_name(self):
41        logger = lldb.formatters.Logger.Logger()
42        return self.sys_params.pointer_size
43
44    def offset_reason(self):
45        logger = lldb.formatters.Logger.Logger()
46        return 2 * self.sys_params.pointer_size
47
48    def description(self):
49        logger = lldb.formatters.Logger.Logger()
50        name_ptr = self.valobj.CreateChildAtOffset(
51            "name", self.offset_name(), self.sys_params.types_cache.id)
52        reason_ptr = self.valobj.CreateChildAtOffset(
53            "reason", self.offset_reason(), self.sys_params.types_cache.id)
54        return 'name:' + CFString.CFString_SummaryProvider(
55            name_ptr, None) + ' reason:' + CFString.CFString_SummaryProvider(reason_ptr, None)
56
57
58class NSUnknownException_SummaryProvider:
59
60    def adjust_for_architecture(self):
61        pass
62
63    def __init__(self, valobj, params):
64        logger = lldb.formatters.Logger.Logger()
65        self.valobj = valobj
66        self.sys_params = params
67        self.update()
68
69    def update(self):
70        logger = lldb.formatters.Logger.Logger()
71        self.adjust_for_architecture()
72
73    def description(self):
74        logger = lldb.formatters.Logger.Logger()
75        stream = lldb.SBStream()
76        self.valobj.GetExpressionPath(stream)
77        name_vo = self.valobj.CreateValueFromExpression(
78            "name", "(NSString*)[" + stream.GetData() + " name]")
79        reason_vo = self.valobj.CreateValueFromExpression(
80            "reason", "(NSString*)[" + stream.GetData() + " reason]")
81        if name_vo.IsValid() and reason_vo.IsValid():
82            return CFString.CFString_SummaryProvider(
83                name_vo, None) + ' ' + CFString.CFString_SummaryProvider(reason_vo, None)
84        return '<variable is not NSException>'
85
86
87def GetSummary_Impl(valobj):
88    logger = lldb.formatters.Logger.Logger()
89    global statistics
90    class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
91        valobj, statistics)
92    if wrapper:
93        return wrapper
94
95    name_string = class_data.class_name()
96    logger >> "class name is: " + str(name_string)
97
98    if name_string == 'NSException':
99        wrapper = NSKnownException_SummaryProvider(
100            valobj, class_data.sys_params)
101        statistics.metric_hit('code_notrun', valobj)
102    else:
103        wrapper = NSUnknownException_SummaryProvider(
104            valobj, class_data.sys_params)
105        statistics.metric_hit(
106            'unknown_class',
107            valobj.GetName() +
108            " seen as " +
109            name_string)
110    return wrapper
111
112
113def NSException_SummaryProvider(valobj, dict):
114    logger = lldb.formatters.Logger.Logger()
115    provider = GetSummary_Impl(valobj)
116    if provider is not None:
117        if isinstance(
118                provider,
119                lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
120            return provider.message()
121        try:
122            summary = provider.description()
123        except:
124            summary = None
125        logger >> "got summary " + str(summary)
126        if summary is None:
127            summary = '<variable is not NSException>'
128        return str(summary)
129    return 'Summary Unavailable'
130
131
132def __lldb_init_module(debugger, dict):
133    debugger.HandleCommand(
134        "type summary add -F NSException.NSException_SummaryProvider NSException")
135