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