xref: /xnu-11215.81.4/tools/lldbmacros/kmemory/vm.py (revision d4514f0bc1d3f944c22d92e68b646ac3fb40d452)
1import struct
2
3from core import (
4    gettype,
5    xnu_format,
6    SBValueFormatter,
7)
8from core.iterators import (
9    RB_HEAD,
10)
11
12from .kmem   import MemoryRange
13from .btlog  import BTLog, BTLibrary
14from .whatis import *
15
16
17@SBValueFormatter.converter("vm_prot")
18def vm_prot_converter(prot):
19    PROT_STR = "-rw?x"
20    return PROT_STR[prot & 1] + PROT_STR[prot & 2] + PROT_STR[prot & 4]
21
22
23class VMMap(object):
24    """ Helper class to manipulate a vm_map_t """
25
26    def __init__(self, vm_map, name=None):
27        self.sbv  = vm_map
28        self.name = name
29        self.rb   = RB_HEAD(
30            vm_map.chkGetValueForExpressionPath(".hdr.rb_head_store"),
31            "entry",
32            self.entry_compare
33        )
34
35        vme_type = gettype('struct vm_map_entry')
36        self.to_entry = vme_type.xContainerOfTransform('store')
37
38    def entry_compare(self, rb_entry, address):
39        vme = self.to_entry(rb_entry)
40
41        if vme.xGetScalarByPath(".links.end") <= address:
42            return 1
43        if address < vme.xGetScalarByPath(".links.start"):
44            return -1
45        return 0
46
47    def find(self, address):
48        ent = self.rb.find(address)
49        return self.to_entry(ent) if ent else None
50
51    def describe(self, verbose=False):
52        fmt = (
53            "VM Map Info\n"
54            " vm map               : {&v:#x} \n"
55        )
56        if self.name:
57            fmt += (
58                " vm map name          : {m.name:s} \n"
59            )
60        fmt += (
61            " pmap                 : {$v.pmap:#x} \n"
62            " vm size              : {$v.size|human_size} ({$v.size:,d} bytes) \n"
63            " entries              : {$v.hdr.nentries} \n"
64            " map range            : "
65                "{$v.hdr.links.start:#x} - {$v.hdr.links.end:#x}\n"
66            " map pgshift          : {$v.hdr.page_shift}\n"
67        )
68        print(xnu_format(fmt, m=self, v=self.sbv))
69
70
71class VMMapEntry(MemoryObject):
72    """ Memory Object for a kernel map memory entry """
73
74    MO_KIND = "kernel map entry"
75
76    def __init__(self, kmem, address, vm_map):
77        super().__init__(kmem, address)
78        self.vm_map = vm_map
79        self.sbv    = vm_map.find(address)
80
81    @property
82    def object_range(self):
83        sbv = self.sbv
84        if sbv:
85            return MemoryRange(
86                sbv.xGetScalarByPath('.links.start'),
87                sbv.xGetScalarByPath('.links.end')
88            )
89
90        base = self.address & ~self.kmem.page_mask
91        return MemoryRange(base, base + self.kmem.page_size)
92
93    @property
94    def vme_offset(self):
95        return self.sbv.xGetScalarByName('vme_offset') << 12
96
97    @property
98    def vme_object_type(self):
99        sbv = self.sbv
100        if sbv.xGetScalarByName('is_sub_map'):
101            return "submap"
102        if sbv.xGetScalarByName('vme_kernel_object'):
103            return "kobject"
104        return "vm object"
105
106    @property
107    def vme_object(self):
108        kmem = self.kmem
109        sbv  = self.sbv
110
111        if sbv.xGetScalarByName('is_sub_map'):
112            addr = sbv.xGetScalarByName('vme_submap') << 2
113            return (addr, kmem.vm_map_type)
114
115        if sbv.xGetScalarByName('vme_kernel_object'):
116            return (kmem.vm_kobject.GetLoadAddress(), kmem.vmo_type)
117
118        packed = sbv.xGetScalarByName('vme_object_or_delta')
119        addr   = kmem.vm_page_packing.unpack(packed)
120        return (addr, kmem.vmo_type)
121
122    @property
123    def pages(self):
124        return self.object_range.size >> self.kmem.page_shift
125
126    def describe(self, verbose=False):
127
128        self.vm_map.describe()
129
130        if not self.sbv:
131            fmt = (
132                "Kernel Map Entry Info\n"
133                " No memory mapped at this address\n"
134            )
135            print(xnu_format(fmt))
136            return
137
138        fmt = (
139            "VM Map Entry Info\n"
140            " vm entry             : {&v:#x}\n"
141            " start / end          : "
142                "{$v.links.start:#x} - {$v.links.end:#x} "
143                "({0.pages:,d} pages)\n"
144            " vm tag               : {$v.vme_alias|vm_kern_tag}\n"
145        )
146        range_id = next((
147            i
148            for i, r in enumerate(self.kmem.kmem_ranges)
149            if r.contains(self.address)
150        ), None)
151        if range_id:
152            fmt += (
153                " vm range id          : {range_id}\n"
154            )
155        fmt += (
156            " protection           : "
157                "{$v.protection|vm_prot}/{$v.max_protection|vm_prot}\n"
158            " vm object            : "
159                "{0.vme_object_type} ({0.vme_object[0]:#x})\n"
160            " entry offset         : {0.vme_offset:#x}\n"
161        )
162        print(xnu_format(fmt, self, v=self.sbv, range_id=range_id))
163
164
165@whatis_provider
166class KernelMapWhatisProvider(WhatisProvider):
167    """
168    Whatis Provider for the kernel map ranges
169    """
170
171    def claims(self, address):
172        kmem = self.kmem
173
174        return any(r.contains(address) for r in kmem.kmem_ranges) or \
175            any(r.contains(address) for r in kmem.iokit_ranges)
176
177    def lookup(self, address):
178        kmem = self.kmem
179
180        if any(r.contains(address) for r in kmem.kmem_ranges):
181            return VMMapEntry(kmem, address, VMMap(kmem.kernel_map, 'kernel_map'))
182
183        idx = next(idx
184            for idx, r
185            in enumerate(kmem.iokit_ranges)
186            if r.contains(address))
187        gps  = kmem.target.chkFindFirstGlobalVariable('gIOKitPageableSpace')
188        map  = gps.chkGetValueForExpressionPath('.maps[{}].map'.format(idx)).Dereference()
189        name = 'gIOKitPageableFixed{}'.format(idx)
190        return VMMapEntry(kmem, address, VMMap(map, name))
191
192
193
194__all__ = [
195    VMMap.__name__,
196    VMMapEntry.__name__,
197    KernelMapWhatisProvider.__name__,
198]
199