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