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