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""" 36 37from __future__ import absolute_import, division, print_function 38 39from builtins import map, filter 40from operator import methodcaller 41from abc import ABCMeta, abstractmethod 42 43import six 44import lldb 45 46from .caching import cache_statically 47 48 49class MetaPointerPolicy(ABCMeta): 50 """ Register a custom pointer policy in global list. """ 51 52 classes = [] 53 54 def __new__(cls, clsname, bases, args): 55 newcls = super(MetaPointerPolicy, cls).__new__(cls, clsname, bases, args) 56 cls.classes.append(newcls) 57 return newcls 58 59 60class Singleton(MetaPointerPolicy): 61 """ Meta class for creation of singleton instances. """ 62 63 _instances = {} 64 65 def __call__(cls, *args, **kwargs): 66 if cls not in cls._instances: 67 cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) 68 return cls._instances[cls] 69 70 71@six.add_metaclass(ABCMeta) 72class PointerPolicy(object): 73 """ Abstract base class common to every custom pointer policy. """ 74 75 @classmethod 76 def match(cls, sbvalue): 77 """ Match pointer representation based on given SBValue. """ 78 matching = filter(bool, map(methodcaller('match', sbvalue), MetaPointerPolicy.classes)) 79 return next(matching, None) 80 81 @abstractmethod 82 def GetPointerSBValue(self, sbvalue): 83 """ Returns pointer value that debugger should operate on. """ 84 85 86# Pointers need to have their TBI byte stripped if in use. TBI KASan, 87# for instance, tags pointers to detect improper memory accesses. Reading 88# values from such tagged pointers fails. 89# 90# Stripping the pointers requires to learn whether TBI is in use or not. 91# We do that by checking presence of 'kasan_tbi_enabled' symbol which only 92# exists on the TBI KASan variant. Since KASan is one of more TBI 93# consumers (along with PAC or Sandbox) this is not an ideal approach. 94# Inspecting respective CPU state would be more appropriate. 95 96 97@six.add_metaclass(Singleton) 98class NativePointer(PointerPolicy): 99 """ Policy for native pointers. 100 101 Strips top bits of a pointer if TBI is in use. Otherwise 102 pointer is used as-is. 103 104 Native pointers do not have any per-pointer attributes so this policy 105 can be singleton instance. 106 """ 107 108 @staticmethod 109 @cache_statically 110 def isKasanTBI(target=None): 111 """ Returns true on TBI KASan targets, false otherwise. """ 112 return any(target.FindGlobalVariables('kasan_tbi_enabled', 1)) 113 114 @classmethod 115 def match(cls, sbvalue): 116 return cls() if sbvalue.GetType().IsPointerType() else None 117 118 def stripTBI(self, sbvalue): 119 """ Strips the TBI byte value. Since the value is not a plain value but 120 represents a value of a variable, a register or an expression the 121 conversion is performed by (re-)creating the value through expression. 122 """ 123 if sbvalue.GetValueAsAddress() != sbvalue.GetValueAsUnsigned(): 124 addr = sbvalue.GetValueAsAddress() 125 sbv_new = sbvalue.CreateValueFromExpression(None, '(void *)' + str(addr)) 126 return sbv_new.Cast(sbvalue.GetType()) 127 128 return sbvalue 129 130 def GetPointerSBValue(self, sbvalue): 131 if self.isKasanTBI(): 132 return self.stripTBI(sbvalue) 133 return sbvalue 134