xref: /xnu-8796.101.5/tools/lldbmacros/core/pointer.py (revision aca3beaa3dfbd42498b42c5e5ce20a938e6554e5)
1*aca3beaaSApple OSS Distributions"""
2*aca3beaaSApple OSS DistributionsCustom pointer support
3*aca3beaaSApple OSS Distributions
4*aca3beaaSApple OSS DistributionsThis module provides support for special pointer types that are not native to the
5*aca3beaaSApple OSS Distributionslanguage used by the target being debugged. Such pointers may be represented as a struct
6*aca3beaaSApple OSS Distributionsor class (for example IOKit's shared pointers).
7*aca3beaaSApple OSS Distributions
8*aca3beaaSApple OSS DistributionsA custom pointer class must subclass the PointerPolicy class and implement all of its
9*aca3beaaSApple OSS Distributionsabstract methods. The MetaPointerPolicy metaclass ensures that all known subclasses are
10*aca3beaaSApple OSS Distributionsregistered in a global list (wherever they are located in the lldb macro sources).
11*aca3beaaSApple OSS Distributions
12*aca3beaaSApple OSS DistributionsA client can obtain a PointerPolicy instance by calling the match method with an SBValue
13*aca3beaaSApple OSS Distributionsinstance as an argument. The returned value is one of:
14*aca3beaaSApple OSS Distributions
15*aca3beaaSApple OSS Distributions    * None - the match was unsuccessful and this SBValue instance is not a pointer.
16*aca3beaaSApple OSS Distributions    * Concrete instance - An instance of the concrete PointerPolicy class that will handle
17*aca3beaaSApple OSS Distributions      pointer operations for the given SBValue.
18*aca3beaaSApple OSS Distributions
19*aca3beaaSApple OSS DistributionsConcrete policy instances implement an API that allows a client to operate on a value
20*aca3beaaSApple OSS Distributionslike a native pointer (for example unwrapping a native pointer from a smart pointer).
21*aca3beaaSApple OSS Distributions
22*aca3beaaSApple OSS DistributionsExample:
23*aca3beaaSApple OSS Distributions
24*aca3beaaSApple OSS Distributions    # Obtain an SBValue instance.
25*aca3beaaSApple OSS Distributions    val = kern.global.GlobalVariable.GetSBValue()
26*aca3beaaSApple OSS Distributions
27*aca3beaaSApple OSS Distributions    # Try to match the pointer policy for the given value.
28*aca3beaaSApple OSS Distributions    policy = PointerPolicy.match(val)
29*aca3beaaSApple OSS Distributions
30*aca3beaaSApple OSS Distributions    # Unwrap the pointer SBValue.
31*aca3beaaSApple OSS Distributions    if policy:
32*aca3beaaSApple OSS Distributions        val = policy.GetPointerSBValue(val)
33*aca3beaaSApple OSS Distributions
34*aca3beaaSApple OSS Distributions    ... Operate on val as usual.
35*aca3beaaSApple OSS Distributions"""
36*aca3beaaSApple OSS Distributions
37*aca3beaaSApple OSS Distributionsfrom __future__ import absolute_import, division, print_function
38*aca3beaaSApple OSS Distributions
39*aca3beaaSApple OSS Distributionsfrom builtins import map, filter
40*aca3beaaSApple OSS Distributionsfrom operator import methodcaller
41*aca3beaaSApple OSS Distributionsfrom abc import ABCMeta, abstractmethod
42*aca3beaaSApple OSS Distributions
43*aca3beaaSApple OSS Distributionsimport six
44*aca3beaaSApple OSS Distributionsimport lldb
45*aca3beaaSApple OSS Distributions
46*aca3beaaSApple OSS Distributionsfrom .caching import cache_statically
47*aca3beaaSApple OSS Distributions
48*aca3beaaSApple OSS Distributions
49*aca3beaaSApple OSS Distributionsclass MetaPointerPolicy(ABCMeta):
50*aca3beaaSApple OSS Distributions    """ Register a custom pointer policy in global list. """
51*aca3beaaSApple OSS Distributions
52*aca3beaaSApple OSS Distributions    classes = []
53*aca3beaaSApple OSS Distributions
54*aca3beaaSApple OSS Distributions    def __new__(cls, clsname, bases, args):
55*aca3beaaSApple OSS Distributions        newcls = super(MetaPointerPolicy, cls).__new__(cls, clsname, bases, args)
56*aca3beaaSApple OSS Distributions        cls.classes.append(newcls)
57*aca3beaaSApple OSS Distributions        return newcls
58*aca3beaaSApple OSS Distributions
59*aca3beaaSApple OSS Distributions
60*aca3beaaSApple OSS Distributionsclass Singleton(MetaPointerPolicy):
61*aca3beaaSApple OSS Distributions    """ Meta class for creation of singleton instances. """
62*aca3beaaSApple OSS Distributions
63*aca3beaaSApple OSS Distributions    _instances = {}
64*aca3beaaSApple OSS Distributions
65*aca3beaaSApple OSS Distributions    def __call__(cls, *args, **kwargs):
66*aca3beaaSApple OSS Distributions        if cls not in cls._instances:
67*aca3beaaSApple OSS Distributions            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
68*aca3beaaSApple OSS Distributions        return cls._instances[cls]
69*aca3beaaSApple OSS Distributions
70*aca3beaaSApple OSS Distributions
71*aca3beaaSApple OSS Distributions@six.add_metaclass(ABCMeta)
72*aca3beaaSApple OSS Distributionsclass PointerPolicy(object):
73*aca3beaaSApple OSS Distributions    """ Abstract base class common to every custom pointer policy. """
74*aca3beaaSApple OSS Distributions
75*aca3beaaSApple OSS Distributions    @classmethod
76*aca3beaaSApple OSS Distributions    def match(cls, sbvalue):
77*aca3beaaSApple OSS Distributions        """ Match pointer representation based on given SBValue. """
78*aca3beaaSApple OSS Distributions        matching = filter(bool, map(methodcaller('match', sbvalue), MetaPointerPolicy.classes))
79*aca3beaaSApple OSS Distributions        return next(matching, None)
80*aca3beaaSApple OSS Distributions
81*aca3beaaSApple OSS Distributions    @abstractmethod
82*aca3beaaSApple OSS Distributions    def GetPointerSBValue(self, sbvalue):
83*aca3beaaSApple OSS Distributions        """ Returns pointer value that debugger should operate on. """
84*aca3beaaSApple OSS Distributions
85*aca3beaaSApple OSS Distributions
86*aca3beaaSApple OSS Distributions# Pointers need to have their TBI byte stripped if in use. TBI KASan,
87*aca3beaaSApple OSS Distributions# for instance, tags pointers to detect improper memory accesses. Reading
88*aca3beaaSApple OSS Distributions# values from such tagged pointers fails.
89*aca3beaaSApple OSS Distributions#
90*aca3beaaSApple OSS Distributions# Stripping the pointers requires to learn whether TBI is in use or not.
91*aca3beaaSApple OSS Distributions# We do that by checking presence of 'kasan_tbi_enabled' symbol which only
92*aca3beaaSApple OSS Distributions# exists on the TBI KASan variant. Since KASan is one of more TBI
93*aca3beaaSApple OSS Distributions# consumers (along with PAC or Sandbox) this is not an ideal approach.
94*aca3beaaSApple OSS Distributions# Inspecting respective CPU state would be more appropriate.
95*aca3beaaSApple OSS Distributions
96*aca3beaaSApple OSS Distributions
97*aca3beaaSApple OSS Distributions@six.add_metaclass(Singleton)
98*aca3beaaSApple OSS Distributionsclass NativePointer(PointerPolicy):
99*aca3beaaSApple OSS Distributions    """ Policy for native pointers.
100*aca3beaaSApple OSS Distributions
101*aca3beaaSApple OSS Distributions        Strips top bits of a pointer if TBI is in use. Otherwise
102*aca3beaaSApple OSS Distributions        pointer is used as-is.
103*aca3beaaSApple OSS Distributions
104*aca3beaaSApple OSS Distributions        Native pointers do not have any per-pointer attributes so this policy
105*aca3beaaSApple OSS Distributions        can be singleton instance.
106*aca3beaaSApple OSS Distributions    """
107*aca3beaaSApple OSS Distributions
108*aca3beaaSApple OSS Distributions    @staticmethod
109*aca3beaaSApple OSS Distributions    @cache_statically
110*aca3beaaSApple OSS Distributions    def isKasanTBI(target=None):
111*aca3beaaSApple OSS Distributions        """ Returns true on TBI KASan targets, false otherwise. """
112*aca3beaaSApple OSS Distributions        return any(target.FindGlobalVariables('kasan_tbi_enabled', 1))
113*aca3beaaSApple OSS Distributions
114*aca3beaaSApple OSS Distributions    @classmethod
115*aca3beaaSApple OSS Distributions    def match(cls, sbvalue):
116*aca3beaaSApple OSS Distributions        return cls() if sbvalue.GetType().IsPointerType() else None
117*aca3beaaSApple OSS Distributions
118*aca3beaaSApple OSS Distributions    def stripTBI(self, sbvalue):
119*aca3beaaSApple OSS Distributions        """ Strips the TBI byte value. Since the value is not a plain value but
120*aca3beaaSApple OSS Distributions            represents a value of a variable, a register or an expression the
121*aca3beaaSApple OSS Distributions            conversion is performed by (re-)creating the value through expression.
122*aca3beaaSApple OSS Distributions        """
123*aca3beaaSApple OSS Distributions        if sbvalue.GetValueAsAddress() != sbvalue.GetValueAsUnsigned():
124*aca3beaaSApple OSS Distributions            addr = sbvalue.GetValueAsAddress()
125*aca3beaaSApple OSS Distributions            sbv_new = sbvalue.CreateValueFromExpression(None, '(void *)' + str(addr))
126*aca3beaaSApple OSS Distributions            return sbv_new.Cast(sbvalue.GetType())
127*aca3beaaSApple OSS Distributions
128*aca3beaaSApple OSS Distributions        return sbvalue
129*aca3beaaSApple OSS Distributions
130*aca3beaaSApple OSS Distributions    def GetPointerSBValue(self, sbvalue):
131*aca3beaaSApple OSS Distributions        if self.isKasanTBI():
132*aca3beaaSApple OSS Distributions            return self.stripTBI(sbvalue)
133*aca3beaaSApple OSS Distributions        return sbvalue
134