1from xnu import * 2import xnudefines 3from kdp import * 4from utils import * 5 6def ReadPhysInt(phys_addr, bitsize = 64, cpuval = None): 7 """ Read a physical memory data based on address. 8 params: 9 phys_addr : int - Physical address to read 10 bitsize : int - defines how many bytes to read. defaults to 64 bit 11 cpuval : None (optional) 12 returns: 13 int - int value read from memory. in case of failure 0xBAD10AD is returned. 14 """ 15 if "kdp" == GetConnectionProtocol(): 16 return KDPReadPhysMEM(phys_addr, bitsize) 17 18 #NO KDP. Attempt to use physical memory 19 paddr_in_kva = kern.PhysToKernelVirt(long(phys_addr)) 20 if paddr_in_kva : 21 if bitsize == 64 : 22 return kern.GetValueFromAddress(paddr_in_kva, 'uint64_t *').GetSBValue().Dereference().GetValueAsUnsigned() 23 if bitsize == 32 : 24 return kern.GetValueFromAddress(paddr_in_kva, 'uint32_t *').GetSBValue().Dereference().GetValueAsUnsigned() 25 if bitsize == 16 : 26 return kern.GetValueFromAddress(paddr_in_kva, 'uint16_t *').GetSBValue().Dereference().GetValueAsUnsigned() 27 if bitsize == 8 : 28 return kern.GetValueFromAddress(paddr_in_kva, 'uint8_t *').GetSBValue().Dereference().GetValueAsUnsigned() 29 return 0xBAD10AD 30 31@lldb_command('readphys') 32def ReadPhys(cmd_args = None): 33 """ Reads the specified untranslated address 34 The argument is interpreted as a physical address, and the 64-bit word 35 addressed is displayed. 36 usage: readphys <nbits> <address> 37 nbits: 8,16,32,64 38 address: 1234 or 0x1234 39 """ 40 if cmd_args == None or len(cmd_args) < 2: 41 print "Insufficient arguments.", ReadPhys.__doc__ 42 return False 43 else: 44 nbits = ArgumentStringToInt(cmd_args[0]) 45 phys_addr = ArgumentStringToInt(cmd_args[1]) 46 print "{0: <#x}".format(ReadPhysInt(phys_addr, nbits)) 47 return True 48 49lldb_alias('readphys8', 'readphys 8 ') 50lldb_alias('readphys16', 'readphys 16 ') 51lldb_alias('readphys32', 'readphys 32 ') 52lldb_alias('readphys64', 'readphys 64 ') 53 54def KDPReadPhysMEM(address, bits): 55 """ Setup the state for READPHYSMEM64 commands for reading data via kdp 56 params: 57 address : int - address where to read the data from 58 bits : int - number of bits in the intval (8/16/32/64) 59 returns: 60 int: read value from memory. 61 0xBAD10AD: if failed to read data. 62 """ 63 retval = 0xBAD10AD 64 if "kdp" != GetConnectionProtocol(): 65 print "Target is not connected over kdp. Nothing to do here." 66 return retval 67 68 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 69 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 70 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 71 if not WriteInt32ToMemoryAddress(0, input_address): 72 return retval 73 74 kdp_pkt_size = GetType('kdp_readphysmem64_req_t').GetByteSize() 75 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 76 return retval 77 78 data_addr = int(addressof(kern.globals.manual_pkt)) 79 pkt = kern.GetValueFromAddress(data_addr, 'kdp_readphysmem64_req_t *') 80 81 header_value =GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_READPHYSMEM64'), length=kdp_pkt_size) 82 83 if ( WriteInt64ToMemoryAddress((header_value), int(addressof(pkt.hdr))) and 84 WriteInt64ToMemoryAddress(address, int(addressof(pkt.address))) and 85 WriteInt32ToMemoryAddress((bits/8), int(addressof(pkt.nbytes))) and 86 WriteInt16ToMemoryAddress(xnudefines.lcpu_self, int(addressof(pkt.lcpu))) 87 ): 88 89 if WriteInt32ToMemoryAddress(1, input_address): 90 # now read data from the kdp packet 91 data_address = unsigned(addressof(kern.GetValueFromAddress(int(addressof(kern.globals.manual_pkt.data)), 'kdp_readphysmem64_reply_t *').data)) 92 if bits == 64 : 93 retval = kern.GetValueFromAddress(data_address, 'uint64_t *').GetSBValue().Dereference().GetValueAsUnsigned() 94 if bits == 32 : 95 retval = kern.GetValueFromAddress(data_address, 'uint32_t *').GetSBValue().Dereference().GetValueAsUnsigned() 96 if bits == 16 : 97 retval = kern.GetValueFromAddress(data_address, 'uint16_t *').GetSBValue().Dereference().GetValueAsUnsigned() 98 if bits == 8 : 99 retval = kern.GetValueFromAddress(data_address, 'uint8_t *').GetSBValue().Dereference().GetValueAsUnsigned() 100 return retval 101 102 103def KDPWritePhysMEM(address, intval, bits): 104 """ Setup the state for WRITEPHYSMEM64 commands for saving data in kdp 105 params: 106 address : int - address where to save the data 107 intval : int - integer value to be stored in memory 108 bits : int - number of bits in the intval (8/16/32/64) 109 returns: 110 boolean: True if the write succeeded. 111 """ 112 if "kdp" != GetConnectionProtocol(): 113 print "Target is not connected over kdp. Nothing to do here." 114 return False 115 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 116 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 117 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 118 if not WriteInt32ToMemoryAddress(0, input_address): 119 return False 120 121 kdp_pkt_size = GetType('kdp_writephysmem64_req_t').GetByteSize() 122 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 123 return False 124 125 data_addr = int(addressof(kern.globals.manual_pkt)) 126 pkt = kern.GetValueFromAddress(data_addr, 'kdp_writephysmem64_req_t *') 127 128 header_value =GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_WRITEPHYSMEM64'), length=kdp_pkt_size) 129 130 if ( WriteInt64ToMemoryAddress((header_value), int(addressof(pkt.hdr))) and 131 WriteInt64ToMemoryAddress(address, int(addressof(pkt.address))) and 132 WriteInt32ToMemoryAddress((bits/8), int(addressof(pkt.nbytes))) and 133 WriteInt16ToMemoryAddress(xnudefines.lcpu_self, int(addressof(pkt.lcpu))) 134 ): 135 136 if bits == 8: 137 if not WriteInt8ToMemoryAddress(intval, int(addressof(pkt.data))): 138 return False 139 if bits == 16: 140 if not WriteInt16ToMemoryAddress(intval, int(addressof(pkt.data))): 141 return False 142 if bits == 32: 143 if not WriteInt32ToMemoryAddress(intval, int(addressof(pkt.data))): 144 return False 145 if bits == 64: 146 if not WriteInt64ToMemoryAddress(intval, int(addressof(pkt.data))): 147 return False 148 if WriteInt32ToMemoryAddress(1, input_address): 149 return True 150 return False 151 152 153def WritePhysInt(phys_addr, int_val, bitsize = 64): 154 """ Write and integer value in a physical memory data based on address. 155 params: 156 phys_addr : int - Physical address to read 157 int_val : int - int value to write in memory 158 bitsize : int - defines how many bytes to read. defaults to 64 bit 159 returns: 160 bool - True if write was successful. 161 """ 162 if "kdp" == GetConnectionProtocol(): 163 if not KDPWritePhysMEM(phys_addr, int_val, bitsize): 164 print "Failed to write via KDP." 165 return False 166 return True 167 #We are not connected via KDP. So do manual math and savings. 168 print "Failed: Write to physical memory is not supported for %s connection." % GetConnectionProtocol() 169 return False 170 171@lldb_command('writephys') 172def WritePhys(cmd_args=None): 173 """ writes to the specified untranslated address 174 The argument is interpreted as a physical address, and the 64-bit word 175 addressed is displayed. 176 usage: writephys <nbits> <address> <value> 177 nbits: 8,16,32,64 178 address: 1234 or 0x1234 179 value: int value to be written 180 ex. (lldb)writephys 16 0x12345abcd 0x25 181 """ 182 if cmd_args == None or len(cmd_args) < 3: 183 print "Invalid arguments.", WritePhys.__doc__ 184 else: 185 nbits = ArgumentStringToInt(cmd_args[0]) 186 phys_addr = ArgumentStringToInt(cmd_args[1]) 187 int_value = ArgumentStringToInt(cmd_args[2]) 188 print WritePhysInt(phys_addr, int_value, nbits) 189 190 191lldb_alias('writephys8', 'writephys 8 ') 192lldb_alias('writephys16', 'writephys 16 ') 193lldb_alias('writephys32', 'writephys 32 ') 194lldb_alias('writephys64', 'writephys 64 ') 195 196 197def _PT_Step(paddr, index, verbose_level = vSCRIPT): 198 """ 199 Step to lower-level page table and print attributes 200 paddr: current page table entry physical address 201 index: current page table entry index (0..511) 202 verbose_level: vHUMAN: print nothing 203 vSCRIPT: print basic information 204 vDETAIL: print basic information and hex table dump 205 returns: (pt_paddr, pt_valid, pt_large) 206 pt_paddr: next level page table entry physical address 207 or null if invalid 208 pt_valid: 1 if $kgm_pt_paddr is valid, 0 if the walk 209 should be aborted 210 pt_large: 1 if kgm_pt_paddr is a page frame address 211 of a large page and not another page table entry 212 """ 213 entry_addr = paddr + (8 * index) 214 entry = ReadPhysInt(entry_addr, 64, xnudefines.lcpu_self ) 215 out_string = '' 216 if verbose_level >= vDETAIL: 217 for pte_loop in range(0, 512): 218 paddr_tmp = paddr + (8 * pte_loop) 219 out_string += "{0: <#020x}:\t {1: <#020x}\n".format(paddr_tmp, ReadPhysInt(paddr_tmp, 64, xnudefines.lcpu_self)) 220 paddr_mask = ~((0xfff<<52) | 0xfff) 221 paddr_large_mask = ~((0xfff<<52) | 0x1fffff) 222 pt_valid = False 223 pt_large = False 224 pt_paddr = 0 225 if verbose_level < vSCRIPT: 226 if entry & 0x1 : 227 pt_valid = True 228 pt_large = False 229 pt_paddr = entry & paddr_mask 230 if entry & (0x1 <<7): 231 pt_large = True 232 pt_paddr = entry & paddr_large_mask 233 else: 234 out_string+= "{0: <#020x}:\n\t{1:#020x}\n\t".format(entry_addr, entry) 235 if entry & 0x1: 236 out_string += " valid" 237 pt_paddr = entry & paddr_mask 238 pt_valid = True 239 else: 240 out_string += " invalid" 241 pt_paddr = 0 242 pt_valid = False 243 #Stop decoding other bits 244 entry = 0 245 if entry & (0x1 << 1): 246 out_string += " writable" 247 else: 248 out_string += " read-only" 249 250 if entry & (0x1 << 2): 251 out_string += " user" 252 else: 253 out_string += " supervisor" 254 255 if entry & (0x1 << 3): 256 out_string += " PWT" 257 258 if entry & (0x1 << 4): 259 out_string += " PCD" 260 261 if entry & (0x1 << 5): 262 out_string += " accessed" 263 264 if entry & (0x1 << 6): 265 out_string += " dirty" 266 267 if entry & (0x1 << 7): 268 out_string += " large" 269 pt_large = True 270 else: 271 pt_large = False 272 273 if entry & (0x1 << 8): 274 out_string += " global" 275 276 if entry & (0x3 << 9): 277 out_string += " avail:{0:x}".format((entry >> 9) & 0x3) 278 279 if entry & (0x1 << 63): 280 out_string += " noexec" 281 print out_string 282 return (pt_paddr, pt_valid, pt_large) 283 284 285 286 287def _PmapL4Walk(pmap_addr_val,vaddr, verbose_level = vSCRIPT): 288 """ Walk the l4 pmap entry. 289 params: pmap_addr_val - core.value representing kernel data of type pmap_addr_t 290 vaddr : int - virtual address to walk 291 """ 292 is_cpu64_bit = int(kern.globals.cpu_64bit) 293 pt_paddr = unsigned(pmap_addr_val) 294 pt_valid = (unsigned(pmap_addr_val) != 0) 295 pt_large = 0 296 pframe_offset = 0 297 if pt_valid and is_cpu64_bit: 298 # Lookup bits 47:39 of linear address in PML4T 299 pt_index = (vaddr >> 39) & 0x1ff 300 pframe_offset = vaddr & 0x7fffffffff 301 if verbose_level > vHUMAN : 302 print "pml4 (index {0:d}):".format(pt_index) 303 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level) 304 if pt_valid: 305 # Lookup bits 38:30 of the linear address in PDPT 306 pt_index = (vaddr >> 30) & 0x1ff 307 pframe_offset = vaddr & 0x3fffffff 308 if verbose_level > vHUMAN: 309 print "pdpt (index {0:d}):".format(pt_index) 310 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level) 311 if pt_valid and not pt_large: 312 #Lookup bits 29:21 of the linear address in PDPT 313 pt_index = (vaddr >> 21) & 0x1ff 314 pframe_offset = vaddr & 0x1fffff 315 if verbose_level > vHUMAN: 316 print "pdt (index {0:d}):".format(pt_index) 317 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level) 318 if pt_valid and not pt_large: 319 #Lookup bits 20:21 of linear address in PT 320 pt_index = (vaddr >> 12) & 0x1ff 321 pframe_offset = vaddr & 0xfff 322 if verbose_level > vHUMAN: 323 print "pt (index {0:d}):".format(pt_index) 324 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level) 325 paddr = 0 326 paddr_isvalid = False 327 if pt_valid: 328 paddr = pt_paddr + pframe_offset 329 paddr_isvalid = True 330 331 if verbose_level > vHUMAN: 332 if paddr_isvalid: 333 pvalue = ReadPhysInt(paddr, 32, xnudefines.lcpu_self) 334 print "phys {0: <#020x}: {1: <#020x}".format(paddr, pvalue) 335 else: 336 print "no translation" 337 338 return paddr 339 340def _PmapWalkARMLevel1Section(tte, vaddr, verbose_level = vSCRIPT): 341 paddr = 0 342 out_string = "" 343 #Supersection or just section? 344 if (tte & 0x40000) == 0x40000: 345 paddr = ( (tte & 0xFF000000) | (vaddr & 0x00FFFFFF) ) 346 else: 347 paddr = ( (tte & 0xFFF00000) | (vaddr & 0x000FFFFF) ) 348 349 if verbose_level >= vSCRIPT: 350 out_string += "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte), tte) 351 #bit [1:0] evaluated in PmapWalkARM 352 # B bit 2 353 b_bit = (tte & 0x4) >> 2 354 # C bit 3 355 c_bit = (tte & 0x8) >> 3 356 #XN bit 4 357 if (tte & 0x10) : 358 out_string += "no-execute" 359 else: 360 out_string += "execute" 361 #Domain bit [8:5] if not supersection 362 if (tte & 0x40000) == 0x0: 363 out_string += " domain ({:d})".format(((tte & 0x1e0) >> 5) ) 364 #IMP bit 9 365 out_string += " imp({:d})".format( ((tte & 0x200) >> 9) ) 366 # AP bit 15 and [11:10] merged to a single 3 bit value 367 access = ( (tte & 0xc00) >> 10 ) | ((tte & 0x8000) >> 13) 368 out_string += xnudefines.arm_level2_access_strings[access] 369 370 #TEX bit [14:12] 371 tex_bits = ((tte & 0x7000) >> 12) 372 #Print TEX, C , B all together 373 out_string += " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format( 374 1 if (tex_bits & 0x4) else 0, 375 1 if (tex_bits & 0x2) else 0, 376 1 if (tex_bits & 0x1) else 0, 377 c_bit, 378 b_bit 379 ) 380 # S bit 16 381 if tte & 0x10000: 382 out_string += " shareable" 383 else: 384 out_string += " not-shareable" 385 # nG bit 17 386 if tte & 0x20000 : 387 out_string += " not-global" 388 else: 389 out_string += " global" 390 # Supersection bit 18 391 if tte & 0x40000: 392 out_string += " supersection" 393 else: 394 out_string += " section" 395 #NS bit 19 396 if tte & 0x80000 : 397 out_string += " no-secure" 398 else: 399 out_string += " secure" 400 401 print out_string 402 return paddr 403 404 405 406def _PmapWalkARMLevel2(tte, vaddr, verbose_level = vSCRIPT): 407 """ Pmap walk the level 2 tte. 408 params: 409 tte - value object 410 vaddr - int 411 returns: str - description of the tte + additional informaiton based on verbose_level 412 """ 413 pte_base = kern.PhysToKernelVirt(tte & 0xFFFFFC00) 414 pte_index = (vaddr >> 12) & 0xFF 415 pte_base_val = kern.GetValueFromAddress(pte_base, 'pt_entry_t *') 416 pte = pte_base_val[pte_index] 417 out_string = '' 418 if verbose_level >= vSCRIPT: 419 out_string += "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte), tte) 420 # bit [1:0] evaluated in PmapWalkARM 421 # NS bit 3 422 if tte & 0x8: 423 out_string += ' no-secure' 424 else: 425 out_string += ' secure' 426 #Domain bit [8:5] 427 out_string += " domain({:d})".format(((tte & 0x1e0) >> 5)) 428 # IMP bit 9 429 out_string += " imp({:d})".format( ((tte & 0x200) >> 9)) 430 out_string += "\n" 431 if verbose_level >= vSCRIPT: 432 out_string += "second-level table (index {:d}):\n".format(pte_index) 433 if verbose_level >= vDETAIL: 434 for i in range(256): 435 tmp = pte_base_val[i] 436 out_string += "{0: <#020x}:\t{1: <#020x}\n".format(addressof(tmp), unsigned(tmp)) 437 438 paddr = 0 439 if pte & 0x2: 440 paddr = (unsigned(pte) & 0xFFFFF000) | (vaddr & 0xFFF) 441 442 if verbose_level >= vSCRIPT: 443 out_string += " {0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(pte), unsigned(pte)) 444 if (pte & 0x3) == 0x0: 445 out_string += " invalid" 446 else: 447 if (pte & 0x3) == 0x1: 448 out_string += " large" 449 # XN bit 15 450 if pte & 0x8000 == 0x8000: 451 out_string+= " no-execute" 452 else: 453 out_string += " execute" 454 else: 455 out_string += " small" 456 # XN bit 0 457 if (pte & 0x1) == 0x01: 458 out_string += " no-execute" 459 else: 460 out_string += " execute" 461 # B bit 2 462 b_bit = (pte & 0x4) >> 2 463 c_bit = (pte & 0x8) >> 3 464 # AP bit 9 and [5:4], merged to a single 3-bit value 465 access = (pte & 0x30) >> 4 | (pte & 0x200) >> 7 466 out_string += xnudefines.arm_level2_access_strings[access] 467 468 #TEX bit [14:12] for large, [8:6] for small 469 tex_bits = ((pte & 0x1c0) >> 6) 470 if (pte & 0x3) == 0x1: 471 tex_bits = ((pte & 0x7000) >> 12) 472 473 # Print TEX, C , B alltogether 474 out_string += " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format( 475 1 if (tex_bits & 0x4) else 0, 476 1 if (tex_bits & 0x2) else 0, 477 1 if (tex_bits & 0x1) else 0, 478 c_bit, 479 b_bit 480 ) 481 # S bit 10 482 if pte & 0x400 : 483 out_string += " shareable" 484 else: 485 out_string += " not-shareable" 486 487 # nG bit 11 488 if pte & 0x800: 489 out_string += " not-global" 490 else: 491 out_string += " global" 492 print out_string 493 return paddr 494 #end of level 2 walking of arm 495 496 497def PmapWalkARM(pmap, vaddr, verbose_level = vHUMAN): 498 """ Pmap walking for ARM kernel. 499 params: 500 pmapval: core.value - representing pmap_t in kernel 501 vaddr: int - integer representing virtual address to walk 502 """ 503 paddr = 0 504 # shift by TTESHIFT (20) to get tte index 505 tte_index = ((vaddr - unsigned(pmap.min)) >> 20 ) 506 tte = pmap.tte[tte_index] 507 if verbose_level >= vSCRIPT: 508 print "First-level table (index {:d}):".format(tte_index) 509 if verbose_level >= vDETAIL: 510 for i in range(0, 4096): 511 ptr = unsigned(addressof(pmap.tte[i])) 512 val = unsigned(pmap.tte[i]) 513 print "{0: <#020x}:\t {1: <#020x}".format(ptr, val) 514 if (tte & 0x3) == 0x1: 515 paddr = _PmapWalkARMLevel2(tte, vaddr, verbose_level) 516 elif (tte & 0x3) == 0x2 : 517 paddr = _PmapWalkARMLevel1Section(tte, vaddr, verbose_level) 518 else: 519 paddr = 0 520 if verbose_level >= vSCRIPT: 521 print "Invalid First-Level Translation Table Entry: {0: #020x}".format(tte) 522 523 if verbose_level >= vHUMAN: 524 if paddr: 525 print "Translation of {:#x} is {:#x}.".format(vaddr, paddr) 526 else: 527 print "(no translation)" 528 529 return paddr 530 531def PmapWalkX86_64(pmapval, vaddr): 532 """ 533 params: pmapval - core.value representing pmap_t in kernel 534 vaddr: int - int representing virtual address to walk 535 """ 536 return _PmapL4Walk(pmapval.pm_cr3, vaddr, config['verbosity']) 537 538def assert_64bit(val): 539 assert(val < 2**64) 540 541ARM64_TTE_SIZE = 8 542ARM64_VMADDR_BITS = 48 543 544def PmapBlockOffsetMaskARM64(level): 545 assert level >= 1 and level <= 3 546 page_size = kern.globals.page_size 547 ttentries = (page_size / ARM64_TTE_SIZE) 548 return page_size * (ttentries ** (3 - level)) - 1 549 550def PmapBlockBaseMaskARM64(level): 551 assert level >= 1 and level <= 3 552 page_size = kern.globals.page_size 553 return ((1 << ARM64_VMADDR_BITS) - 1) & ~PmapBlockOffsetMaskARM64(level) 554 555def PmapIndexMaskARM64(level): 556 assert level >= 1 and level <= 3 557 page_size = kern.globals.page_size 558 ttentries = (page_size / ARM64_TTE_SIZE) 559 return page_size * (ttentries ** (3 - level) * (ttentries - 1)) 560 561def PmapIndexDivideARM64(level): 562 assert level >= 1 and level <= 3 563 page_size = kern.globals.page_size 564 ttentries = (page_size / ARM64_TTE_SIZE) 565 return page_size * (ttentries ** (3 - level)) 566 567def PmapTTnIndexARM64(vaddr, level): 568 assert(type(vaddr) in (long, int)) 569 assert_64bit(vaddr) 570 571 return (vaddr & PmapIndexMaskARM64(level)) // PmapIndexDivideARM64(level) 572 573def PmapDecodeTTEARM64(tte, level): 574 assert(type(tte) == long) 575 assert(type(level) == int) 576 assert_64bit(tte) 577 578 if tte & 0x1 == 0x1: 579 if (tte & 0x2 == 0x2) and (level != 0x3): 580 print "Type = Table pointer." 581 print "Table addr = {:#x}.".format(tte & 0xfffffffff000) 582 print "PXN = {:#x}.".format((tte >> 59) & 0x1) 583 print "XN = {:#x}.".format((tte >> 60) & 0x1) 584 print "AP = {:#x}.".format((tte >> 61) & 0x3) 585 print "NS = {:#x}".format(tte >> 63) 586 else: 587 print "Type = Block." 588 print "AttrIdx = {:#x}.".format((tte >> 2) & 0x7) 589 print "NS = {:#x}.".format((tte >> 5) & 0x1) 590 print "AP = {:#x}.".format((tte >> 6) & 0x3) 591 print "SH = {:#x}.".format((tte >> 8) & 0x3) 592 print "AF = {:#x}.".format((tte >> 10) & 0x1) 593 print "nG = {:#x}.".format((tte >> 11) & 0x1) 594 print "HINT = {:#x}.".format((tte >> 52) & 0x1) 595 print "PXN = {:#x}.".format((tte >> 53) & 0x1) 596 print "XN = {:#x}.".format((tte >> 54) & 0x1) 597 print "SW Use = {:#x}.".format((tte >> 55) & 0xf) 598 else: 599 print "Invalid." 600 601 return 602 603def PmapWalkARM64(pmap, vaddr, verbose_level = vHUMAN): 604 assert(type(pmap) == core.cvalue.value) 605 assert(type(vaddr) in (long, int)) 606 page_size = kern.globals.page_size 607 page_offset_mask = (page_size - 1) 608 page_base_mask = ((1 << ARM64_VMADDR_BITS) - 1) & (~page_offset_mask) 609 610 assert_64bit(vaddr) 611 paddr = -1 612 613 tt1_index = PmapTTnIndexARM64(vaddr, 1) 614 tt2_index = PmapTTnIndexARM64(vaddr, 2) 615 tt3_index = PmapTTnIndexARM64(vaddr, 3) 616 617 # L1 618 tte = long(unsigned(pmap.tte[tt1_index])) 619 assert(type(tte) == long) 620 assert_64bit(tte) 621 622 if verbose_level >= vSCRIPT: 623 print "L1 entry: {:#x}".format(tte) 624 if verbose_level >= vDETAIL: 625 PmapDecodeTTEARM64(tte, 1) 626 627 if tte & 0x1 == 0x1: 628 # Check for L1 block entry 629 if tte & 0x2 == 0x0: 630 # Handle L1 block entry 631 paddr = tte & PmapBlockBaseMaskARM64(1) 632 paddr = paddr | (vaddr & PmapBlockOffsetMaskARM64(1)) 633 print "phys: {:#x}".format(paddr) 634 else: 635 # Handle L1 table entry 636 l2_phys = (tte & page_base_mask) + (ARM64_TTE_SIZE * tt2_index) 637 assert(type(l2_phys) == long) 638 639 l2_virt = kern.PhysToKernelVirt(l2_phys) 640 assert(type(l2_virt) == long) 641 642 if verbose_level >= vDETAIL: 643 print "L2 physical address: {:#x}. L2 virtual address: {:#x}".format(l2_phys, l2_virt) 644 645 # L2 646 ttep = kern.GetValueFromAddress(l2_virt, "tt_entry_t*") 647 tte = long(unsigned(dereference(ttep))) 648 assert(type(tte) == long) 649 650 if verbose_level >= vSCRIPT: 651 print "L2 entry: {:#0x}".format(tte) 652 if verbose_level >= vDETAIL: 653 PmapDecodeTTEARM64(tte, 2) 654 655 if tte & 0x1 == 0x1: 656 # Check for L2 block entry 657 if tte & 0x2 == 0x0: 658 # Handle L2 block entry 659 paddr = tte & PmapBlockBaseMaskARM64(2) 660 paddr = paddr | (vaddr & PmapBlockOffsetMaskARM64(2)) 661 else: 662 # Handle L2 table entry 663 l3_phys = (tte & page_base_mask) + (ARM64_TTE_SIZE * tt3_index) 664 assert(type(l3_phys) == long) 665 666 l3_virt = kern.PhysToKernelVirt(l3_phys) 667 assert(type(l3_virt) == long) 668 669 if verbose_level >= vDETAIL: 670 print "L3 physical address: {:#x}. L3 virtual address: {:#x}".format(l3_phys, l3_virt) 671 672 # L3 673 ttep = kern.GetValueFromAddress(l3_virt, "tt_entry_t*") 674 tte = long(unsigned(dereference(ttep))) 675 assert(type(tte) == long) 676 677 if verbose_level >= vSCRIPT: 678 print "L3 entry: {:#0x}".format(tte) 679 if verbose_level >= vDETAIL: 680 PmapDecodeTTEARM64(tte, 3) 681 682 if tte & 0x3 == 0x3: 683 paddr = tte & page_base_mask 684 paddr = paddr | (vaddr & page_offset_mask) 685 elif verbose_level >= vHUMAN: 686 print "L3 entry invalid: {:#x}\n".format(tte) 687 elif verbose_level >= vHUMAN: # tte & 0x1 == 0x1 688 print "L2 entry invalid: {:#x}\n".format(tte) 689 elif verbose_level >= vHUMAN: 690 print "L1 entry invalid: {:#x}\n".format(tte) 691 692 if verbose_level >= vHUMAN: 693 if paddr: 694 print "Translation of {:#x} is {:#x}.".format(vaddr, paddr) 695 else: 696 print "(no translation)" 697 698 return paddr 699 700def PmapWalk(pmap, vaddr, verbose_level = vHUMAN): 701 if kern.arch == 'x86_64': 702 return PmapWalkX86_64(pmap, vaddr) 703 elif kern.arch == 'arm': 704 return PmapWalkARM(pmap, vaddr, verbose_level) 705 elif kern.arch == 'arm64': 706 return PmapWalkARM64(pmap, vaddr, verbose_level) 707 else: 708 raise NotImplementedError("PmapWalk does not support {0}".format(kern.arch)) 709 710@lldb_command('pmap_walk') 711def PmapWalkHelper(cmd_args=None): 712 """ Perform a page-table walk in <pmap> for <virtual_address>. 713 Syntax: (lldb) pmap_walk <pmap> <virtual_address> [-v] 714 Multiple -v's can be specified for increased verbosity 715 """ 716 if cmd_args == None or len(cmd_args) < 2: 717 raise ArgumentError("Too few arguments to pmap_walk.") 718 719 pmap = kern.GetValueAsType(cmd_args[0], 'pmap_t') 720 addr = unsigned(kern.GetValueFromAddress(cmd_args[1], 'void *')) 721 PmapWalk(pmap, addr, config['verbosity']) 722 return 723