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