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