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