xref: /xnu-10002.61.3/tools/lldbmacros/kmemory/whatis.py (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
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