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