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