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