1from __future__ import absolute_import, division, print_function 2 3from builtins import object 4 5import operator 6import six 7 8from abc import ABCMeta, abstractmethod 9from core import ( 10 caching, 11 gettype, 12) 13from six import add_metaclass 14 15from .kmem import KMem, MemoryRange 16 17 18@add_metaclass(ABCMeta) 19class MemoryObject(object): 20 """ 21 Abstract class for any memory object resolved by Whatis 22 """ 23 24 MO_KIND = None 25 26 def __init__(self, kmem, address): 27 self.kmem = kmem 28 self.address = address 29 30 @property 31 @abstractmethod 32 def object_range(self): 33 """ 34 Returns the MemoryRange for this object if any 35 """ 36 pass 37 38 @abstractmethod 39 def describe(self, verbose=False): 40 """ 41 Method to describe oneself for whatis 42 """ 43 pass 44 45 46class UnknownMemoryObject(MemoryObject): 47 """ Fallback Memory Object for unclaimed addresses """ 48 49 MO_KIND = "<unknown>" 50 51 @property 52 def object_range(self): 53 return None 54 55 def describe(self, verbose=False): 56 print("Unknown Memory Object Info") 57 print(" this address is not recognized, please implement/extend") 58 print(" a WhatisProvider to recognize it in the future") 59 print() 60 61 62class WhatisProvider(object): 63 """ Base class for Whatis Providers """ 64 65 """ 66 List of direct subclasses, used for resolution 67 """ 68 subproviders = [] 69 70 """ 71 Evaluation cost of this provider 72 73 the higher the cost, the later it gets evaluated. 74 """ 75 76 COST = 10 77 78 def __init__(self, target): 79 self._children = list(cls(target) for cls in self.__class__.subproviders) 80 self.kmem = KMem.get_shared() 81 self.target = target 82 83 @staticmethod 84 @caching.cache_statically 85 def get_shared(target=None): 86 return WhatisProvider(target) 87 88 def find_provider(self, address): 89 return next(iter(c for c in self._children if c.claims(address)), self) 90 91 def claims(self, address): 92 """ 93 Returns whether this provider "claims" the address 94 95 @param address (int) 96 The addrress being considered 97 """ 98 99 pass 100 101 def lookup(self, address): 102 """ 103 Lookup a memory object by address 104 105 @param address (int) 106 The addrress being considered 107 108 @returns (MemoryObject) 109 """ 110 111 return UnknownMemoryObject(self.kmem, address) 112 113 def describe(self, mo): 114 """ 115 Describe a memory object 116 117 Providers can override this method to add more information. 118 """ 119 120 print(( 121 "Basic Info\n" 122 " kind : {0.__class__.MO_KIND}\n" 123 " address : {0.address:#x}" 124 ).format(mo)) 125 126 mem_r = mo.object_range 127 if mem_r is None: 128 print(" {:<21s}: Unknown".format("object range")) 129 else: 130 print(" {:<21s}: {r.start:#x} - {r.end:#x} ({r.size:,d} bytes)".format( 131 "object range", r = mem_r)) 132 address = mo.address 133 if address != mem_r.start: 134 print(" {:<21s}: {:,d} from start, {:,d} to end".format( 135 "offset", address - mem_r.start, mem_r.end - address)) 136 137 print() 138 139 140def whatis_provider(cls): 141 """ 142 Class decorator for Whatis providers 143 """ 144 145 if not issubclass(cls, WhatisProvider): 146 raise TypeError("{} is not a subclass of WhatisProvider".format(cls.__name__)) 147 148 cls.subproviders = [] 149 base = cls.__base__ 150 151 if base != object: 152 k = next(( 153 k for k in ['claims', 'lookup'] 154 if getattr(cls, k) == getattr(base, k) 155 ), None) 156 if k: 157 raise TypeError("{} must reimplement function '{}'".format(cls.__name__, k)) 158 159 base.subproviders.append(cls) 160 base.subproviders.sort(key=operator.attrgetter('COST')) 161 162 return cls 163 164 165__all__ = [ 166 whatis_provider.__name__, 167 168 MemoryObject.__name__, 169 WhatisProvider.__name__, 170] 171