1from xnu import * 2import xnudefines 3from kdp import * 4from utils import * 5import struct 6 7def ReadPhysInt(phys_addr, bitsize = 64, cpuval = None): 8 """ Read a physical memory data based on address. 9 params: 10 phys_addr : int - Physical address to read 11 bitsize : int - defines how many bytes to read. defaults to 64 bit 12 cpuval : None (optional) 13 returns: 14 int - int value read from memory. in case of failure 0xBAD10AD is returned. 15 """ 16 if "kdp" == GetConnectionProtocol(): 17 return KDPReadPhysMEM(phys_addr, bitsize) 18 19 #NO KDP. Attempt to use physical memory 20 paddr_in_kva = kern.PhysToKernelVirt(long(phys_addr)) 21 if paddr_in_kva : 22 if bitsize == 64 : 23 return kern.GetValueFromAddress(paddr_in_kva, 'uint64_t *').GetSBValue().Dereference().GetValueAsUnsigned() 24 if bitsize == 32 : 25 return kern.GetValueFromAddress(paddr_in_kva, 'uint32_t *').GetSBValue().Dereference().GetValueAsUnsigned() 26 if bitsize == 16 : 27 return kern.GetValueFromAddress(paddr_in_kva, 'uint16_t *').GetSBValue().Dereference().GetValueAsUnsigned() 28 if bitsize == 8 : 29 return kern.GetValueFromAddress(paddr_in_kva, 'uint8_t *').GetSBValue().Dereference().GetValueAsUnsigned() 30 return 0xBAD10AD 31 32@lldb_command('readphys') 33def ReadPhys(cmd_args = None): 34 """ Reads the specified untranslated address 35 The argument is interpreted as a physical address, and the 64-bit word 36 addressed is displayed. 37 usage: readphys <nbits> <address> 38 nbits: 8,16,32,64 39 address: 1234 or 0x1234 40 """ 41 if cmd_args == None or len(cmd_args) < 2: 42 print "Insufficient arguments.", ReadPhys.__doc__ 43 return False 44 else: 45 nbits = ArgumentStringToInt(cmd_args[0]) 46 phys_addr = ArgumentStringToInt(cmd_args[1]) 47 print "{0: <#x}".format(ReadPhysInt(phys_addr, nbits)) 48 return True 49 50lldb_alias('readphys8', 'readphys 8 ') 51lldb_alias('readphys16', 'readphys 16 ') 52lldb_alias('readphys32', 'readphys 32 ') 53lldb_alias('readphys64', 'readphys 64 ') 54 55def KDPReadPhysMEM(address, bits): 56 """ Setup the state for READPHYSMEM64 commands for reading data via kdp 57 params: 58 address : int - address where to read the data from 59 bits : int - number of bits in the intval (8/16/32/64) 60 returns: 61 int: read value from memory. 62 0xBAD10AD: if failed to read data. 63 """ 64 retval = 0xBAD10AD 65 if "kdp" != GetConnectionProtocol(): 66 print "Target is not connected over kdp. Nothing to do here." 67 return retval 68 69 if "hwprobe" == KDPMode(): 70 # Send the proper KDP command and payload to the bare metal debug tool via a KDP server 71 addr_for_kdp = struct.unpack("<Q", struct.pack(">Q", address))[0] 72 byte_count = struct.unpack("<I", struct.pack(">I", bits/8))[0] 73 packet = "{0:016x}{1:08x}{2:04x}".format(addr_for_kdp, byte_count, 0x0) 74 75 ret_obj = lldb.SBCommandReturnObject() 76 ci = lldb.debugger.GetCommandInterpreter() 77 ci.HandleCommand('process plugin packet send -c 25 -p {0}'.format(packet), ret_obj) 78 79 if ret_obj.Succeeded(): 80 value = ret_obj.GetOutput() 81 82 if bits == 64 : 83 pack_fmt = "<Q" 84 unpack_fmt = ">Q" 85 if bits == 32 : 86 pack_fmt = "<I" 87 unpack_fmt = ">I" 88 if bits == 16 : 89 pack_fmt = "<H" 90 unpack_fmt = ">H" 91 if bits == 8 : 92 pack_fmt = "<B" 93 unpack_fmt = ">B" 94 95 retval = struct.unpack(unpack_fmt, struct.pack(pack_fmt, int(value[-((bits/4)+1):], 16)))[0] 96 97 else: 98 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 99 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 100 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 101 102 if not WriteInt32ToMemoryAddress(0, input_address): 103 return retval 104 105 kdp_pkt_size = GetType('kdp_readphysmem64_req_t').GetByteSize() 106 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 107 return retval 108 109 data_addr = int(addressof(kern.globals.manual_pkt)) 110 pkt = kern.GetValueFromAddress(data_addr, 'kdp_readphysmem64_req_t *') 111 112 header_value =GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_READPHYSMEM64'), length=kdp_pkt_size) 113 114 if ( WriteInt64ToMemoryAddress((header_value), int(addressof(pkt.hdr))) and 115 WriteInt64ToMemoryAddress(address, int(addressof(pkt.address))) and 116 WriteInt32ToMemoryAddress((bits/8), int(addressof(pkt.nbytes))) and 117 WriteInt16ToMemoryAddress(xnudefines.lcpu_self, int(addressof(pkt.lcpu))) 118 ): 119 120 if WriteInt32ToMemoryAddress(1, input_address): 121 # now read data from the kdp packet 122 data_address = unsigned(addressof(kern.GetValueFromAddress(int(addressof(kern.globals.manual_pkt.data)), 'kdp_readphysmem64_reply_t *').data)) 123 if bits == 64 : 124 retval = kern.GetValueFromAddress(data_address, 'uint64_t *').GetSBValue().Dereference().GetValueAsUnsigned() 125 if bits == 32 : 126 retval = kern.GetValueFromAddress(data_address, 'uint32_t *').GetSBValue().Dereference().GetValueAsUnsigned() 127 if bits == 16 : 128 retval = kern.GetValueFromAddress(data_address, 'uint16_t *').GetSBValue().Dereference().GetValueAsUnsigned() 129 if bits == 8 : 130 retval = kern.GetValueFromAddress(data_address, 'uint8_t *').GetSBValue().Dereference().GetValueAsUnsigned() 131 132 return retval 133 134 135def KDPWritePhysMEM(address, intval, bits): 136 """ Setup the state for WRITEPHYSMEM64 commands for saving data in kdp 137 params: 138 address : int - address where to save the data 139 intval : int - integer value to be stored in memory 140 bits : int - number of bits in the intval (8/16/32/64) 141 returns: 142 boolean: True if the write succeeded. 143 """ 144 if "kdp" != GetConnectionProtocol(): 145 print "Target is not connected over kdp. Nothing to do here." 146 return False 147 148 if "hwprobe" == KDPMode(): 149 # Send the proper KDP command and payload to the bare metal debug tool via a KDP server 150 addr_for_kdp = struct.unpack("<Q", struct.pack(">Q", address))[0] 151 byte_count = struct.unpack("<I", struct.pack(">I", bits/8))[0] 152 153 if bits == 64 : 154 pack_fmt = ">Q" 155 unpack_fmt = "<Q" 156 if bits == 32 : 157 pack_fmt = ">I" 158 unpack_fmt = "<I" 159 if bits == 16 : 160 pack_fmt = ">H" 161 unpack_fmt = "<H" 162 if bits == 8 : 163 pack_fmt = ">B" 164 unpack_fmt = "<B" 165 166 data_val = struct.unpack(unpack_fmt, struct.pack(pack_fmt, intval))[0] 167 168 packet = "{0:016x}{1:08x}{2:04x}{3:016x}".format(addr_for_kdp, byte_count, 0x0, data_val) 169 170 ret_obj = lldb.SBCommandReturnObject() 171 ci = lldb.debugger.GetCommandInterpreter() 172 ci.HandleCommand('process plugin packet send -c 26 -p {0}'.format(packet), ret_obj) 173 174 if ret_obj.Succeeded(): 175 return True 176 else: 177 return False 178 179 else: 180 input_address = unsigned(addressof(kern.globals.manual_pkt.input)) 181 len_address = unsigned(addressof(kern.globals.manual_pkt.len)) 182 data_address = unsigned(addressof(kern.globals.manual_pkt.data)) 183 if not WriteInt32ToMemoryAddress(0, input_address): 184 return False 185 186 kdp_pkt_size = GetType('kdp_writephysmem64_req_t').GetByteSize() + (bits / 8) 187 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address): 188 return False 189 190 data_addr = int(addressof(kern.globals.manual_pkt)) 191 pkt = kern.GetValueFromAddress(data_addr, 'kdp_writephysmem64_req_t *') 192 193 header_value =GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_WRITEPHYSMEM64'), length=kdp_pkt_size) 194 195 if ( WriteInt64ToMemoryAddress((header_value), int(addressof(pkt.hdr))) and 196 WriteInt64ToMemoryAddress(address, int(addressof(pkt.address))) and 197 WriteInt32ToMemoryAddress((bits/8), int(addressof(pkt.nbytes))) and 198 WriteInt16ToMemoryAddress(xnudefines.lcpu_self, int(addressof(pkt.lcpu))) 199 ): 200 201 if bits == 8: 202 if not WriteInt8ToMemoryAddress(intval, int(addressof(pkt.data))): 203 return False 204 if bits == 16: 205 if not WriteInt16ToMemoryAddress(intval, int(addressof(pkt.data))): 206 return False 207 if bits == 32: 208 if not WriteInt32ToMemoryAddress(intval, int(addressof(pkt.data))): 209 return False 210 if bits == 64: 211 if not WriteInt64ToMemoryAddress(intval, int(addressof(pkt.data))): 212 return False 213 if WriteInt32ToMemoryAddress(1, input_address): 214 return True 215 return False 216 217 218def WritePhysInt(phys_addr, int_val, bitsize = 64): 219 """ Write and integer value in a physical memory data based on address. 220 params: 221 phys_addr : int - Physical address to read 222 int_val : int - int value to write in memory 223 bitsize : int - defines how many bytes to read. defaults to 64 bit 224 returns: 225 bool - True if write was successful. 226 """ 227 if "kdp" == GetConnectionProtocol(): 228 if not KDPWritePhysMEM(phys_addr, int_val, bitsize): 229 print "Failed to write via KDP." 230 return False 231 return True 232 #We are not connected via KDP. So do manual math and savings. 233 print "Failed: Write to physical memory is not supported for %s connection." % GetConnectionProtocol() 234 return False 235 236@lldb_command('writephys') 237def WritePhys(cmd_args=None): 238 """ writes to the specified untranslated address 239 The argument is interpreted as a physical address, and the 64-bit word 240 addressed is displayed. 241 usage: writephys <nbits> <address> <value> 242 nbits: 8,16,32,64 243 address: 1234 or 0x1234 244 value: int value to be written 245 ex. (lldb)writephys 16 0x12345abcd 0x25 246 """ 247 if cmd_args == None or len(cmd_args) < 3: 248 print "Invalid arguments.", WritePhys.__doc__ 249 else: 250 nbits = ArgumentStringToInt(cmd_args[0]) 251 phys_addr = ArgumentStringToInt(cmd_args[1]) 252 int_value = ArgumentStringToInt(cmd_args[2]) 253 print WritePhysInt(phys_addr, int_value, nbits) 254 255 256lldb_alias('writephys8', 'writephys 8 ') 257lldb_alias('writephys16', 'writephys 16 ') 258lldb_alias('writephys32', 'writephys 32 ') 259lldb_alias('writephys64', 'writephys 64 ') 260 261 262def _PT_Step(paddr, index, verbose_level = vSCRIPT): 263 """ 264 Step to lower-level page table and print attributes 265 paddr: current page table entry physical address 266 index: current page table entry index (0..511) 267 verbose_level: vHUMAN: print nothing 268 vSCRIPT: print basic information 269 vDETAIL: print basic information and hex table dump 270 returns: (pt_paddr, pt_valid, pt_large) 271 pt_paddr: next level page table entry physical address 272 or null if invalid 273 pt_valid: 1 if $kgm_pt_paddr is valid, 0 if the walk 274 should be aborted 275 pt_large: 1 if kgm_pt_paddr is a page frame address 276 of a large page and not another page table entry 277 """ 278 entry_addr = paddr + (8 * index) 279 entry = ReadPhysInt(entry_addr, 64, xnudefines.lcpu_self ) 280 out_string = '' 281 if verbose_level >= vDETAIL: 282 for pte_loop in range(0, 512): 283 paddr_tmp = paddr + (8 * pte_loop) 284 out_string += "{0: <#020x}:\t {1: <#020x}\n".format(paddr_tmp, ReadPhysInt(paddr_tmp, 64, xnudefines.lcpu_self)) 285 paddr_mask = ~((0xfff<<52) | 0xfff) 286 paddr_large_mask = ~((0xfff<<52) | 0x1fffff) 287 pt_valid = False 288 pt_large = False 289 pt_paddr = 0 290 if verbose_level < vSCRIPT: 291 if entry & 0x1 : 292 pt_valid = True 293 pt_large = False 294 pt_paddr = entry & paddr_mask 295 if entry & (0x1 <<7): 296 pt_large = True 297 pt_paddr = entry & paddr_large_mask 298 else: 299 out_string+= "{0: <#020x}:\n\t{1:#020x}\n\t".format(entry_addr, entry) 300 if entry & 0x1: 301 out_string += " valid" 302 pt_paddr = entry & paddr_mask 303 pt_valid = True 304 else: 305 out_string += " invalid" 306 pt_paddr = 0 307 pt_valid = False 308 if entry & (0x1 << 62): 309 out_string += " compressed" 310 #Stop decoding other bits 311 entry = 0 312 if entry & (0x1 << 1): 313 out_string += " writable" 314 else: 315 out_string += " read-only" 316 317 if entry & (0x1 << 2): 318 out_string += " user" 319 else: 320 out_string += " supervisor" 321 322 if entry & (0x1 << 3): 323 out_string += " PWT" 324 325 if entry & (0x1 << 4): 326 out_string += " PCD" 327 328 if entry & (0x1 << 5): 329 out_string += " accessed" 330 331 if entry & (0x1 << 6): 332 out_string += " dirty" 333 334 if entry & (0x1 << 7): 335 out_string += " large" 336 pt_large = True 337 else: 338 pt_large = False 339 340 if entry & (0x1 << 8): 341 out_string += " global" 342 343 if entry & (0x3 << 9): 344 out_string += " avail:{0:x}".format((entry >> 9) & 0x3) 345 346 if entry & (0x1 << 63): 347 out_string += " noexec" 348 print out_string 349 return (pt_paddr, pt_valid, pt_large) 350 351def _PT_StepEPT(paddr, index, verbose_level = vSCRIPT): 352 """ 353 Step to lower-level page table and print attributes for EPT pmap 354 paddr: current page table entry physical address 355 index: current page table entry index (0..511) 356 verbose_level: vHUMAN: print nothing 357 vSCRIPT: print basic information 358 vDETAIL: print basic information and hex table dump 359 returns: (pt_paddr, pt_valid, pt_large) 360 pt_paddr: next level page table entry physical address 361 or null if invalid 362 pt_valid: 1 if $kgm_pt_paddr is valid, 0 if the walk 363 should be aborted 364 pt_large: 1 if kgm_pt_paddr is a page frame address 365 of a large page and not another page table entry 366 """ 367 entry_addr = paddr + (8 * index) 368 entry = ReadPhysInt(entry_addr, 64, xnudefines.lcpu_self ) 369 out_string = '' 370 if verbose_level >= vDETAIL: 371 for pte_loop in range(0, 512): 372 paddr_tmp = paddr + (8 * pte_loop) 373 out_string += "{0: <#020x}:\t {1: <#020x}\n".format(paddr_tmp, ReadPhysInt(paddr_tmp, 64, xnudefines.lcpu_self)) 374 paddr_mask = ~((0xfff<<52) | 0xfff) 375 paddr_large_mask = ~((0xfff<<52) | 0x1fffff) 376 pt_valid = False 377 pt_large = False 378 pt_paddr = 0 379 if verbose_level < vSCRIPT: 380 if entry & 0x7 : 381 pt_valid = True 382 pt_large = False 383 pt_paddr = entry & paddr_mask 384 if entry & (0x1 <<7): 385 pt_large = True 386 pt_paddr = entry & paddr_large_mask 387 else: 388 out_string+= "{0: <#020x}:\n\t{1:#020x}\n\t".format(entry_addr, entry) 389 if entry & 0x7: 390 out_string += "valid" 391 pt_paddr = entry & paddr_mask 392 pt_valid = True 393 else: 394 out_string += "invalid" 395 pt_paddr = 0 396 pt_valid = False 397 if entry & (0x1 << 62): 398 out_string += " compressed" 399 #Stop decoding other bits 400 entry = 0 401 if entry & 0x1: 402 out_string += " readable" 403 else: 404 out_string += " no read" 405 if entry & (0x1 << 1): 406 out_string += " writable" 407 else: 408 out_string += " no write" 409 410 if entry & (0x1 << 2): 411 out_string += " executable" 412 else: 413 out_string += " no exec" 414 415 ctype = entry & 0x38 416 if ctype == 0x30: 417 out_string += " cache-WB" 418 elif ctype == 0x28: 419 out_string += " cache-WP" 420 elif ctype == 0x20: 421 out_string += " cache-WT" 422 elif ctype == 0x8: 423 out_string += " cache-WC" 424 else: 425 out_string += " cache-NC" 426 427 if (entry & 0x40) == 0x40: 428 out_string += " Ignore-PTA" 429 430 if (entry & 0x100) == 0x100: 431 out_string += " accessed" 432 433 if (entry & 0x200) == 0x200: 434 out_string += " dirty" 435 436 if entry & (0x1 << 7): 437 out_string += " large" 438 pt_large = True 439 else: 440 pt_large = False 441 print out_string 442 return (pt_paddr, pt_valid, pt_large) 443 444def _PmapL4Walk(pmap_addr_val,vaddr, ept_pmap, verbose_level = vSCRIPT): 445 """ Walk the l4 pmap entry. 446 params: pmap_addr_val - core.value representing kernel data of type pmap_addr_t 447 vaddr : int - virtual address to walk 448 """ 449 pt_paddr = unsigned(pmap_addr_val) 450 pt_valid = (unsigned(pmap_addr_val) != 0) 451 pt_large = 0 452 pframe_offset = 0 453 if pt_valid: 454 # Lookup bits 47:39 of linear address in PML4T 455 pt_index = (vaddr >> 39) & 0x1ff 456 pframe_offset = vaddr & 0x7fffffffff 457 if verbose_level > vHUMAN : 458 print "pml4 (index {0:d}):".format(pt_index) 459 if not(ept_pmap): 460 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level) 461 else: 462 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level) 463 if pt_valid: 464 # Lookup bits 38:30 of the linear address in PDPT 465 pt_index = (vaddr >> 30) & 0x1ff 466 pframe_offset = vaddr & 0x3fffffff 467 if verbose_level > vHUMAN: 468 print "pdpt (index {0:d}):".format(pt_index) 469 if not(ept_pmap): 470 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level) 471 else: 472 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level) 473 if pt_valid and not pt_large: 474 #Lookup bits 29:21 of the linear address in PDPT 475 pt_index = (vaddr >> 21) & 0x1ff 476 pframe_offset = vaddr & 0x1fffff 477 if verbose_level > vHUMAN: 478 print "pdt (index {0:d}):".format(pt_index) 479 if not(ept_pmap): 480 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level) 481 else: 482 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level) 483 if pt_valid and not pt_large: 484 #Lookup bits 20:21 of linear address in PT 485 pt_index = (vaddr >> 12) & 0x1ff 486 pframe_offset = vaddr & 0xfff 487 if verbose_level > vHUMAN: 488 print "pt (index {0:d}):".format(pt_index) 489 if not(ept_pmap): 490 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level) 491 else: 492 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level) 493 paddr = 0 494 paddr_isvalid = False 495 if pt_valid: 496 paddr = pt_paddr + pframe_offset 497 paddr_isvalid = True 498 499 if verbose_level > vHUMAN: 500 if paddr_isvalid: 501 pvalue = ReadPhysInt(paddr, 32, xnudefines.lcpu_self) 502 print "phys {0: <#020x}: {1: <#020x}".format(paddr, pvalue) 503 else: 504 print "no translation" 505 506 return paddr 507 508def PmapDecodeTTEARM(tte, level, verbose_level): 509 """ Display the bits of an ARM translation table or page table entry 510 in human-readable form. 511 tte: integer value of the TTE/PTE 512 level: translation table level. Valid values are 1 or 2. 513 verbose_level: verbosity. vHUMAN, vSCRIPT, vDETAIL 514 """ 515 out_string = "" 516 if level == 1 and (tte & 0x3) == 0x2: 517 if verbose_level < vSCRIPT: 518 return 519 520 #bit [1:0] evaluated in PmapWalkARM 521 # B bit 2 522 b_bit = (tte & 0x4) >> 2 523 # C bit 3 524 c_bit = (tte & 0x8) >> 3 525 #XN bit 4 526 if (tte & 0x10) : 527 out_string += "no-execute" 528 else: 529 out_string += "execute" 530 #Domain bit [8:5] if not supersection 531 if (tte & 0x40000) == 0x0: 532 out_string += " domain ({:d})".format(((tte & 0x1e0) >> 5) ) 533 #IMP bit 9 534 out_string += " imp({:d})".format( ((tte & 0x200) >> 9) ) 535 # AP bit 15 and [11:10] merged to a single 3 bit value 536 access = ( (tte & 0xc00) >> 10 ) | ((tte & 0x8000) >> 13) 537 out_string += xnudefines.arm_level2_access_strings[access] 538 539 #TEX bit [14:12] 540 tex_bits = ((tte & 0x7000) >> 12) 541 #Print TEX, C , B all together 542 out_string += " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format( 543 1 if (tex_bits & 0x4) else 0, 544 1 if (tex_bits & 0x2) else 0, 545 1 if (tex_bits & 0x1) else 0, 546 c_bit, 547 b_bit 548 ) 549 # S bit 16 550 if tte & 0x10000: 551 out_string += " shareable" 552 else: 553 out_string += " not-shareable" 554 # nG bit 17 555 if tte & 0x20000 : 556 out_string += " not-global" 557 else: 558 out_string += " global" 559 # Supersection bit 18 560 if tte & 0x40000: 561 out_string += " supersection" 562 else: 563 out_string += " section" 564 #NS bit 19 565 if tte & 0x80000 : 566 out_string += " no-secure" 567 else: 568 out_string += " secure" 569 570 elif level == 1 and (tte & 0x3) == 0x1: 571 572 if verbose_level >= vSCRIPT: 573 # bit [1:0] evaluated in PmapWalkARM 574 # NS bit 3 575 if tte & 0x8: 576 out_string += ' no-secure' 577 else: 578 out_string += ' secure' 579 #Domain bit [8:5] 580 out_string += " domain({:d})".format(((tte & 0x1e0) >> 5)) 581 # IMP bit 9 582 out_string += " imp({:d})".format( ((tte & 0x200) >> 9)) 583 out_string += "\n" 584 585 elif level == 2: 586 pte = tte 587 if verbose_level >= vSCRIPT: 588 if (pte & 0x3) == 0x0: 589 out_string += " invalid" 590 else: 591 if (pte & 0x3) == 0x1: 592 out_string += " large" 593 # XN bit 15 594 if pte & 0x8000 == 0x8000: 595 out_string+= " no-execute" 596 else: 597 out_string += " execute" 598 else: 599 out_string += " small" 600 # XN bit 0 601 if (pte & 0x1) == 0x01: 602 out_string += " no-execute" 603 else: 604 out_string += " execute" 605 # B bit 2 606 b_bit = (pte & 0x4) >> 2 607 c_bit = (pte & 0x8) >> 3 608 # AP bit 9 and [5:4], merged to a single 3-bit value 609 access = (pte & 0x30) >> 4 | (pte & 0x200) >> 7 610 out_string += xnudefines.arm_level2_access_strings[access] 611 612 #TEX bit [14:12] for large, [8:6] for small 613 tex_bits = ((pte & 0x1c0) >> 6) 614 if (pte & 0x3) == 0x1: 615 tex_bits = ((pte & 0x7000) >> 12) 616 617 # Print TEX, C , B alltogether 618 out_string += " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format( 619 1 if (tex_bits & 0x4) else 0, 620 1 if (tex_bits & 0x2) else 0, 621 1 if (tex_bits & 0x1) else 0, 622 c_bit, 623 b_bit 624 ) 625 # S bit 10 626 if pte & 0x400 : 627 out_string += " shareable" 628 else: 629 out_string += " not-shareable" 630 631 # nG bit 11 632 if pte & 0x800: 633 out_string += " not-global" 634 else: 635 out_string += " global" 636 637 print out_string 638 639 640def _PmapWalkARMLevel1Section(tte, vaddr, verbose_level = vSCRIPT): 641 paddr = 0 642 #Supersection or just section? 643 if (tte & 0x40000) == 0x40000: 644 paddr = ( (tte & 0xFF000000) | (vaddr & 0x00FFFFFF) ) 645 else: 646 paddr = ( (tte & 0xFFF00000) | (vaddr & 0x000FFFFF) ) 647 648 if verbose_level >= vSCRIPT: 649 print "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte), tte), 650 651 PmapDecodeTTEARM(tte, 1, verbose_level) 652 653 return paddr 654 655 656 657def _PmapWalkARMLevel2(tte, vaddr, verbose_level = vSCRIPT): 658 """ Pmap walk the level 2 tte. 659 params: 660 tte - value object 661 vaddr - int 662 returns: str - description of the tte + additional informaiton based on verbose_level 663 """ 664 pte_base = kern.PhysToKernelVirt(tte & 0xFFFFFC00) 665 pte_index = (vaddr >> 12) & 0xFF 666 pte_base_val = kern.GetValueFromAddress(pte_base, 'pt_entry_t *') 667 pte = pte_base_val[pte_index] 668 669 paddr = 0 670 if pte & 0x2: 671 paddr = (unsigned(pte) & 0xFFFFF000) | (vaddr & 0xFFF) 672 673 if verbose_level >= vSCRIPT: 674 print "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte), tte), 675 676 PmapDecodeTTEARM(tte, 1, verbose_level) 677 if verbose_level >= vSCRIPT: 678 print "second-level table (index {:d}):".format(pte_index) 679 if verbose_level >= vDETAIL: 680 for i in range(256): 681 tmp = pte_base_val[i] 682 print "{0: <#020x}:\t{1: <#020x}".format(addressof(tmp), unsigned(tmp)) 683 684 if verbose_level >= vSCRIPT: 685 print " {0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(pte), unsigned(pte)), 686 687 PmapDecodeTTEARM(pte, 2, verbose_level) 688 689 return paddr 690 #end of level 2 walking of arm 691 692 693def PmapWalkARM(pmap, vaddr, verbose_level = vHUMAN): 694 """ Pmap walking for ARM kernel. 695 params: 696 pmapval: core.value - representing pmap_t in kernel 697 vaddr: int - integer representing virtual address to walk 698 """ 699 paddr = 0 700 # shift by TTESHIFT (20) to get tte index 701 # Assume all L1 indexing starts at VA 0...for our purposes it does, 702 # as that's where all user pmaps start, and the kernel pmap contains 703 # 4 L1 pages (the lower 2 of which are unused after bootstrap) 704 tte_index = vaddr >> 20 705 tte = pmap.tte[tte_index] 706 if verbose_level >= vSCRIPT: 707 print "First-level table (index {:d}):".format(tte_index) 708 if verbose_level >= vDETAIL: 709 for i in range(0, pmap.tte_index_max): 710 ptr = unsigned(addressof(pmap.tte[i])) 711 val = unsigned(pmap.tte[i]) 712 print "{0: <#020x}:\t {1: <#020x}".format(ptr, val) 713 if (tte & 0x3) == 0x1: 714 paddr = _PmapWalkARMLevel2(tte, vaddr, verbose_level) 715 elif (tte & 0x3) == 0x2 : 716 paddr = _PmapWalkARMLevel1Section(tte, vaddr, verbose_level) 717 else: 718 paddr = 0 719 if verbose_level >= vSCRIPT: 720 print "Invalid First-Level Translation Table Entry: {0: #020x}".format(tte) 721 722 if verbose_level >= vHUMAN: 723 if paddr: 724 print "Translation of {:#x} is {:#x}.".format(vaddr, paddr) 725 else: 726 print "(no translation)" 727 728 return paddr 729 730def PmapWalkX86_64(pmapval, vaddr, verbose_level = vSCRIPT): 731 """ 732 params: pmapval - core.value representing pmap_t in kernel 733 vaddr: int - int representing virtual address to walk 734 """ 735 if pmapval.pm_cr3 != 0: 736 if verbose_level > vHUMAN: 737 print "Using normal Intel PMAP from pm_cr3\n" 738 return _PmapL4Walk(pmapval.pm_cr3, vaddr, 0, config['verbosity']) 739 else: 740 if verbose_level > vHUMAN: 741 print "Using EPT pmap from pm_eptp\n" 742 return _PmapL4Walk(pmapval.pm_eptp, vaddr, 1, config['verbosity']) 743 744def assert_64bit(val): 745 assert(val < 2**64) 746 747ARM64_TTE_SIZE = 8 748ARM64_TTE_SHIFT = 3 749ARM64_VMADDR_BITS = 48 750 751def PmapBlockOffsetMaskARM64(page_size, level): 752 assert level >= 0 and level <= 3 753 ttentries = (page_size / ARM64_TTE_SIZE) 754 return page_size * (ttentries ** (3 - level)) - 1 755 756def PmapBlockBaseMaskARM64(page_size, level): 757 assert level >= 0 and level <= 3 758 return ((1 << ARM64_VMADDR_BITS) - 1) & ~PmapBlockOffsetMaskARM64(page_size, level) 759 760def PmapDecodeTTEARM64(tte, level, stage2 = False, is_iommu_tte = False): 761 """ Display the bits of an ARM64 translation table or page table entry 762 in human-readable form. 763 tte: integer value of the TTE/PTE 764 level: translation table level. Valid values are 1, 2, or 3. 765 is_iommu_tte: True if the TTE is from an IOMMU's page table, False otherwise. 766 """ 767 assert(type(level) == int) 768 assert_64bit(tte) 769 770 if tte & 0x1 == 0x0: 771 print("Invalid.") 772 return 773 774 if (tte & 0x2 == 0x2) and (level != 0x3): 775 print "Type = Table pointer." 776 print "Table addr = {:#x}.".format(tte & 0xfffffffff000) 777 778 if not stage2: 779 print "PXN = {:#x}.".format((tte >> 59) & 0x1) 780 print "XN = {:#x}.".format((tte >> 60) & 0x1) 781 print "AP = {:#x}.".format((tte >> 61) & 0x3) 782 print "NS = {:#x}.".format(tte >> 63) 783 else: 784 print "Type = Block." 785 786 if stage2: 787 print "S2 MemAttr = {:#x}.".format((tte >> 2) & 0xf) 788 else: 789 attr_index = (tte >> 2) & 0x7 790 attr_string = { 0: 'WRITEBACK', 1: 'WRITECOMB', 2: 'WRITETHRU', 791 3: 'CACHE DISABLE', 4: 'INNERWRITEBACK', 5: 'POSTED', 792 6: 'POSTED_REORDERED', 7: 'POSTED_COMBINED_REORDERED' } 793 794 # Only show the string version of the AttrIdx for CPU mappings since 795 # these values don't apply to IOMMU mappings. 796 if is_iommu_tte: 797 print "AttrIdx = {:#x}.".format(attr_index) 798 else: 799 print "AttrIdx = {:#x} ({:s}).".format(attr_index, attr_string[attr_index]) 800 print "NS = {:#x}.".format((tte >> 5) & 0x1) 801 802 if stage2: 803 print "S2AP = {:#x}.".format((tte >> 6) & 0x3) 804 else: 805 print "AP = {:#x}.".format((tte >> 6) & 0x3) 806 807 print "SH = {:#x}.".format((tte >> 8) & 0x3) 808 print "AF = {:#x}.".format((tte >> 10) & 0x1) 809 810 if not stage2: 811 print "nG = {:#x}.".format((tte >> 11) & 0x1) 812 813 print "HINT = {:#x}.".format((tte >> 52) & 0x1) 814 815 if stage2: 816 print "S2XN = {:#x}.".format((tte >> 53) & 0x3) 817 else: 818 print "PXN = {:#x}.".format((tte >> 53) & 0x1) 819 print "XN = {:#x}.".format((tte >> 54) & 0x1) 820 821 print "SW Use = {:#x}.".format((tte >> 55) & 0xf) 822 823 return 824 825def PmapTTnIndexARM64(vaddr, pmap_pt_attr): 826 pta_max_level = unsigned(pmap_pt_attr.pta_max_level) 827 828 tt_index = [] 829 for i in range(pta_max_level + 1): 830 tt_index.append((vaddr & unsigned(pmap_pt_attr.pta_level_info[i].index_mask)) \ 831 >> unsigned(pmap_pt_attr.pta_level_info[i].shift)) 832 833 return tt_index 834 835def PmapWalkARM64(pmap_pt_attr, root_tte, vaddr, verbose_level = vHUMAN): 836 assert(type(vaddr) in (long, int)) 837 assert_64bit(vaddr) 838 assert_64bit(root_tte) 839 840 # Obtain pmap attributes 841 page_size = pmap_pt_attr.pta_page_size 842 page_offset_mask = (page_size - 1) 843 page_base_mask = ((1 << ARM64_VMADDR_BITS) - 1) & (~page_offset_mask) 844 tt_index = PmapTTnIndexARM64(vaddr, pmap_pt_attr) 845 stage2 = bool(pmap_pt_attr.stage2 if hasattr(pmap_pt_attr, 'stage2') else False) 846 847 # The pmap starts at a page table level that is defined by register 848 # values; the root level can be obtained from the attributes structure 849 level = unsigned(pmap_pt_attr.pta_root_level) 850 851 root_tt_index = tt_index[level] 852 root_pgtable_num_ttes = (unsigned(pmap_pt_attr.pta_level_info[level].index_mask) >> \ 853 unsigned(pmap_pt_attr.pta_level_info[level].shift)) + 1 854 tte = long(unsigned(root_tte[root_tt_index])) 855 856 # Walk the page tables 857 paddr = -1 858 max_level = unsigned(pmap_pt_attr.pta_max_level) 859 is_valid = True 860 is_leaf = False 861 862 while (level <= max_level): 863 if verbose_level >= vSCRIPT: 864 print "L{} entry: {:#x}".format(level, tte) 865 if verbose_level >= vDETAIL: 866 PmapDecodeTTEARM64(tte, level, stage2) 867 868 if tte & 0x1 == 0x0: 869 if verbose_level >= vHUMAN: 870 print "L{} entry invalid: {:#x}\n".format(level, tte) 871 872 is_valid = False 873 break 874 875 # Handle leaf entry 876 if tte & 0x2 == 0x0 or level == max_level: 877 base_mask = page_base_mask if level == max_level else PmapBlockBaseMaskARM64(page_size, level) 878 offset_mask = page_offset_mask if level == max_level else PmapBlockOffsetMaskARM64(page_size, level) 879 paddr = tte & base_mask 880 paddr = paddr | (vaddr & offset_mask) 881 882 if level != max_level: 883 print "phys: {:#x}".format(paddr) 884 885 is_leaf = True 886 break 887 else: 888 # Handle page table entry 889 next_phys = (tte & page_base_mask) + (ARM64_TTE_SIZE * tt_index[level + 1]) 890 assert(type(next_phys) == long) 891 892 next_virt = kern.PhysToKernelVirt(next_phys) 893 assert(type(next_virt) == long) 894 895 if verbose_level >= vDETAIL: 896 print "L{} physical address: {:#x}. L{} virtual address: {:#x}".format(level + 1, next_phys, level + 1, next_virt) 897 898 ttep = kern.GetValueFromAddress(next_virt, "tt_entry_t*") 899 tte = long(unsigned(dereference(ttep))) 900 assert(type(tte) == long) 901 902 # We've parsed one level, so go to the next level 903 assert(level <= 3) 904 level = level + 1 905 906 907 if verbose_level >= vHUMAN: 908 if paddr: 909 print "Translation of {:#x} is {:#x}.".format(vaddr, paddr) 910 else: 911 print "(no translation)" 912 913 return paddr 914 915def PmapWalk(pmap, vaddr, verbose_level = vHUMAN): 916 if kern.arch == 'x86_64': 917 return PmapWalkX86_64(pmap, vaddr, verbose_level) 918 elif kern.arch == 'arm': 919 return PmapWalkARM(pmap, vaddr, verbose_level) 920 elif kern.arch.startswith('arm64'): 921 # Obtain pmap attributes from pmap structure 922 pmap_pt_attr = pmap.pmap_pt_attr if hasattr(pmap, 'pmap_pt_attr') else kern.globals.native_pt_attr 923 return PmapWalkARM64(pmap_pt_attr, pmap.tte, vaddr, verbose_level) 924 else: 925 raise NotImplementedError("PmapWalk does not support {0}".format(kern.arch)) 926 927@lldb_command('pmap_walk') 928def PmapWalkHelper(cmd_args=None): 929 """ Perform a page-table walk in <pmap> for <virtual_address>. 930 Syntax: (lldb) pmap_walk <pmap> <virtual_address> [-v] [-e] 931 Multiple -v's can be specified for increased verbosity 932 """ 933 if cmd_args == None or len(cmd_args) < 2: 934 raise ArgumentError("Too few arguments to pmap_walk.") 935 936 pmap = kern.GetValueAsType(cmd_args[0], 'pmap_t') 937 addr = ArgumentStringToInt(cmd_args[1]) 938 PmapWalk(pmap, addr, config['verbosity']) 939 return 940 941def GetMemoryAttributesFromUser(requested_type): 942 pmap_attr_dict = { 943 '4k' : kern.globals.pmap_pt_attr_4k, 944 '16k' : kern.globals.pmap_pt_attr_16k, 945 '16k_s2' : kern.globals.pmap_pt_attr_16k_stage2 if hasattr(kern.globals, 'pmap_pt_attr_16k_stage2') else None, 946 } 947 948 requested_type = requested_type.lower() 949 if requested_type not in pmap_attr_dict: 950 return None 951 952 return pmap_attr_dict[requested_type] 953 954@lldb_command('ttep_walk') 955def TTEPWalkPHelper(cmd_args=None): 956 """ Perform a page-table walk in <root_ttep> for <virtual_address>. 957 Syntax: (lldb) ttep_walk <root_ttep> <virtual_address> [4k|16k|16k_s2] [-v] [-e] 958 Multiple -v's can be specified for increased verbosity 959 """ 960 if cmd_args == None or len(cmd_args) < 2: 961 raise ArgumentError("Too few arguments to ttep_walk.") 962 963 if not kern.arch.startswith('arm64'): 964 raise NotImplementedError("ttep_walk does not support {0}".format(kern.arch)) 965 966 tte = kern.GetValueFromAddress(kern.PhysToKernelVirt(ArgumentStringToInt(cmd_args[0])), 'unsigned long *') 967 addr = ArgumentStringToInt(cmd_args[1]) 968 969 pmap_pt_attr = kern.globals.native_pt_attr if len(cmd_args) < 3 else GetMemoryAttributesFromUser(cmd_args[2]) 970 if pmap_pt_attr is None: 971 raise ArgumentError("Invalid translation attribute type.") 972 973 return PmapWalkARM64(pmap_pt_attr, tte, addr, config['verbosity']) 974 975@lldb_command('decode_tte') 976def DecodeTTE(cmd_args=None): 977 """ Decode the bits in the TTE/PTE value specified <tte_val> for translation level <level> and stage [s1|s2] 978 Syntax: (lldb) decode_tte <tte_val> <level> [s1|s2] 979 """ 980 if cmd_args == None or len(cmd_args) < 2: 981 raise ArgumentError("Too few arguments to decode_tte.") 982 if len(cmd_args) > 2 and cmd_args[2] not in ["s1", "s2"]: 983 raise ArgumentError("{} is not a valid stage of translation.".format(cmd_args[2])) 984 if kern.arch == 'arm': 985 PmapDecodeTTEARM(kern.GetValueFromAddress(cmd_args[0], "unsigned long"), ArgumentStringToInt(cmd_args[1]), vSCRIPT) 986 elif kern.arch.startswith('arm64'): 987 stage2 = True if len(cmd_args) > 2 and cmd_args[2] == "s2" else False 988 PmapDecodeTTEARM64(ArgumentStringToInt(cmd_args[0]), ArgumentStringToInt(cmd_args[1]), stage2) 989 else: 990 raise NotImplementedError("decode_tte does not support {0}".format(kern.arch)) 991 992 993PVH_HIGH_FLAGS_ARM64 = (1 << 62) | (1 << 61) | (1 << 60) | (1 << 59) | (1 << 58) | (1 << 57) | (1 << 56) 994PVH_HIGH_FLAGS_ARM32 = (1 << 31) 995 996def PVDumpPTE(pvep, ptep, verbose_level = vHUMAN): 997 """ Dump information about a single mapping retrieved by the pv_head_table. 998 999 pvep: Either a pointer to the PVE object if the PVH entry is PVH_TYPE_PVEP, 1000 or None if type PVH_TYPE_PTEP. 1001 ptep: For type PVH_TYPE_PTEP this should just be the raw PVH entry with 1002 the high flags already set (the type bits don't need to be cleared). 1003 For type PVH_TYPE_PVEP this will be the value retrieved from the 1004 pve_ptep[] array. 1005 """ 1006 if kern.arch.startswith('arm64'): 1007 iommu_flag = 0x4 1008 iommu_table_flag = 1 << 63 1009 else: 1010 iommu_flag = 0 1011 iommu_table_flag = 0 1012 1013 # AltAcct status is only stored in the ptep for PVH_TYPE_PVEP entries. 1014 if pvep is not None and (ptep & 0x1): 1015 # Note: It's not possible for IOMMU mappings to be marked as alt acct so 1016 # setting this string is mutually exclusive with setting the IOMMU strings. 1017 pte_str = ' (alt acct)' 1018 else: 1019 pte_str = '' 1020 1021 if pvep is not None: 1022 pve_str = 'PVEP {:#x}, '.format(pvep) 1023 else: 1024 pve_str = '' 1025 1026 # For PVH_TYPE_PTEP, this clears out the type bits. For PVH_TYPE_PVEP, this 1027 # either does nothing or clears out the AltAcct bit. 1028 ptep = ptep & ~0x3 1029 1030 # When printing with extra verbosity, print an extra newline that describes 1031 # who owns the mapping. 1032 extra_str = '' 1033 1034 if ptep & iommu_flag: 1035 # The mapping is an IOMMU Mapping 1036 ptep = ptep & ~iommu_flag 1037 1038 # Due to LLDB automatically setting all the high bits of pointers, when 1039 # ptep is retrieved from the pve_ptep[] array, LLDB will automatically set 1040 # the iommu_table_flag, which means this check only works for PVH entries 1041 # of type PVH_TYPE_PTEP (since those PTEPs come directly from the PVH 1042 # entry which has the right casting applied to avoid this issue). 1043 # 1044 # Why don't we just do the same casting for pve_ptep[] you ask? Well not 1045 # for a lack of trying, that's for sure. If you can figure out how to 1046 # cast that array correctly, then be my guest. 1047 if ptep & iommu_table_flag: 1048 pte_str = ' (IOMMU table), entry' 1049 1050 ptd = GetPtDesc(KVToPhysARM(ptep)) 1051 iommu = dereference(ptd.iommu) 1052 else: 1053 # Instead of dumping the PTE (since we don't have that), dump the 1054 # descriptor object used by the IOMMU state (t8020dart/nvme_ppl/etc). 1055 # 1056 # This works because later on when the "ptep" is dereferenced as a 1057 # PTE pointer (uint64_t pointer), the descriptor pointer will be 1058 # dumped as that's the first 64-bit value in the IOMMU state object. 1059 pte_str = ' (IOMMU state), descriptor' 1060 ptep = ptep | iommu_table_flag 1061 iommu = dereference(kern.GetValueFromAddress(ptep, 'ppl_iommu_state *')) 1062 1063 # For IOMMU mappings, dump who owns the mapping as the extra string. 1064 extra_str = 'Mapped by {:s}'.format(dereference(iommu.desc).name) 1065 if unsigned(iommu.name) is not 0: 1066 extra_str += '/{:s}'.format(iommu.name) 1067 extra_str += ' (iommu state: {:x})'.format(addressof(iommu)) 1068 else: 1069 # The mapping is a CPU Mapping 1070 pte_str += ', entry' 1071 ptd = GetPtDesc(KVToPhysARM(ptep)) 1072 if ptd.pmap == kern.globals.kernel_pmap: 1073 extra_str = "Mapped by kernel task (kernel_pmap: {:#x})".format(ptd.pmap) 1074 elif verbose_level >= vDETAIL: 1075 task = TaskForPmapHelper(ptd.pmap) 1076 extra_str = "Mapped by user task (pmap: {:#x}, task: {:s})".format(ptd.pmap, "{:#x}".format(task) if task is not None else "<unknown>") 1077 try: 1078 print "{:s}PTEP {:#x}{:s}: {:#x}".format(pve_str, ptep, pte_str, dereference(kern.GetValueFromAddress(ptep, 'pt_entry_t *'))) 1079 except: 1080 print "{:s}PTEP {:#x}{:s}: <unavailable>".format(pve_str, ptep, pte_str) 1081 1082 if verbose_level >= vDETAIL: 1083 print " |-- {:s}".format(extra_str) 1084 1085def PVWalkARM(pai, verbose_level = vHUMAN): 1086 """ Walk a physical-to-virtual reverse mapping list maintained by the arm pmap. 1087 1088 pai: physical address index (PAI) corresponding to the pv_head_table 1089 entry to walk. 1090 verbose_level: Set to vSCRIPT or higher to print extra info around the 1091 the pv_head_table/pp_attr_table flags and to dump the 1092 pt_desc_t object if the type is a PTD. 1093 """ 1094 # LLDB will automatically try to make pointer values dereferencable by 1095 # setting the upper bits if they aren't set. We need to parse the flags 1096 # stored in the upper bits later, so cast the pv_head_table to an array of 1097 # integers to get around this "feature". We'll add the upper bits back 1098 # manually before deref'ing anything. 1099 pv_head_table = cast(kern.GetGlobalVariable('pv_head_table'), "uintptr_t*") 1100 pvh_raw = unsigned(pv_head_table[pai]) 1101 pvh = pvh_raw 1102 pvh_type = pvh & 0x3 1103 1104 print "PVH raw value: {:#x}".format(pvh_raw) 1105 if kern.arch.startswith('arm64'): 1106 pvh = pvh | PVH_HIGH_FLAGS_ARM64 1107 else: 1108 pvh = pvh | PVH_HIGH_FLAGS_ARM32 1109 1110 if pvh_type == 0: 1111 print "PVH type: NULL" 1112 elif pvh_type == 3: 1113 print "PVH type: page-table descriptor ({:#x})".format(pvh & ~0x3) 1114 elif pvh_type == 2: 1115 print "PVH type: single PTE" 1116 PVDumpPTE(None, pvh, verbose_level) 1117 elif pvh_type == 1: 1118 pvep = pvh & ~0x3 1119 print "PVH type: PTE list" 1120 pve_ptep_idx = 0 1121 while pvep != 0: 1122 pve = kern.GetValueFromAddress(pvep, "pv_entry_t *") 1123 1124 if pve.pve_ptep[pve_ptep_idx] != 0: 1125 PVDumpPTE(pvep, pve.pve_ptep[pve_ptep_idx], verbose_level) 1126 1127 pve_ptep_idx += 1 1128 if pve_ptep_idx == 2: 1129 pve_ptep_idx = 0 1130 pvep = unsigned(pve.pve_next) 1131 1132 if verbose_level >= vDETAIL: 1133 if (pvh_type == 1) or (pvh_type == 2): 1134 # Dump pv_head_table flags when there's a valid mapping. 1135 pvh_flags = [] 1136 1137 if pvh_raw & (1 << 62): 1138 pvh_flags.append("CPU") 1139 if pvh_raw & (1 << 60): 1140 pvh_flags.append("EXEC") 1141 if pvh_raw & (1 << 59): 1142 pvh_flags.append("LOCKDOWN_KC") 1143 if pvh_raw & (1 << 58): 1144 pvh_flags.append("HASHED") 1145 if pvh_raw & (1 << 57): 1146 pvh_flags.append("LOCKDOWN_CS") 1147 if pvh_raw & (1 << 56): 1148 pvh_flags.append("LOCKDOWN_RO") 1149 if kern.arch.startswith('arm64') and pvh_raw & (1 << 61): 1150 pvh_flags.append("LOCK") 1151 elif kern.arch == 'arm' and pvh_raw & (1 << 31): 1152 pvh_flags.append("LOCK") 1153 1154 print "PVH Flags: {}".format(pvh_flags) 1155 1156 # Always dump pp_attr_table flags (these can be updated even if there aren't mappings). 1157 ppattr = unsigned(kern.globals.pp_attr_table[pai]) 1158 print "PPATTR raw value: {:#x}".format(ppattr) 1159 1160 ppattr_flags = ["WIMG ({:#x})".format(ppattr & 0x3F)] 1161 if ppattr & 0x40: 1162 ppattr_flags.append("REFERENCED") 1163 if ppattr & 0x80: 1164 ppattr_flags.append("MODIFIED") 1165 if ppattr & 0x100: 1166 ppattr_flags.append("INTERNAL") 1167 if ppattr & 0x200: 1168 ppattr_flags.append("REUSABLE") 1169 if ppattr & 0x400: 1170 ppattr_flags.append("ALTACCT") 1171 if ppattr & 0x800: 1172 ppattr_flags.append("NOENCRYPT") 1173 if ppattr & 0x1000: 1174 ppattr_flags.append("REFFAULT") 1175 if ppattr & 0x2000: 1176 ppattr_flags.append("MODFAULT") 1177 if ppattr & 0x4000: 1178 ppattr_flags.append("MONITOR") 1179 if ppattr & 0x8000: 1180 ppattr_flags.append("NO_MONITOR") 1181 1182 print "PPATTR Flags: {}".format(ppattr_flags) 1183 1184 if pvh_type == 3: 1185 def RunLldbCmdHelper(command): 1186 """Helper for dumping an LLDB command right before executing it 1187 and printing the results. 1188 command: The LLDB command (as a string) to run. 1189 1190 Example input: "p/x kernel_pmap". 1191 """ 1192 print "\nExecuting: {:s}\n{:s}".format(command, lldb_run_command(command)) 1193 # Dump the page table descriptor object 1194 ptd = kern.GetValueFromAddress(pvh & ~0x3, 'pt_desc_t *') 1195 RunLldbCmdHelper("p/x *(pt_desc_t*)" + hex(ptd)) 1196 1197 # Depending on the system, more than one ptd_info can be associated 1198 # with a single PTD. Only dump the first PTD info and assume the 1199 # user knows to dump the rest if they're on one of those systems. 1200 RunLldbCmdHelper("p/x ((pt_desc_t*)" + hex(ptd) + ")->ptd_info[0]") 1201 1202@lldb_command('pv_walk') 1203def PVWalk(cmd_args=None): 1204 """ Show mappings for <physical_address | PAI> tracked in the PV list. 1205 Syntax: (lldb) pv_walk <physical_address | PAI> [-vv] 1206 1207 Extra verbosity will pretty print the pv_head_table/pp_attr_table flags 1208 as well as dump the page table descriptor (PTD) struct if the entry is a 1209 PTD. 1210 """ 1211 if cmd_args == None or len(cmd_args) < 1: 1212 raise ArgumentError("Too few arguments to pv_walk.") 1213 if not kern.arch.startswith('arm'): 1214 raise NotImplementedError("pv_walk does not support {0}".format(kern.arch)) 1215 1216 pa = kern.GetValueFromAddress(cmd_args[0], 'unsigned long') 1217 1218 # If the input is already a PAI, this function will return the input unchanged. 1219 # This function also ensures that the physical address is kernel-managed. 1220 pai = ConvertPhysAddrToPai(pa) 1221 1222 PVWalkARM(pai, config['verbosity']) 1223 1224@lldb_command('kvtophys') 1225def KVToPhys(cmd_args=None): 1226 """ Translate a kernel virtual address to the corresponding physical address. 1227 Assumes the virtual address falls within the kernel static region. 1228 Syntax: (lldb) kvtophys <kernel virtual address> 1229 """ 1230 if cmd_args == None or len(cmd_args) < 1: 1231 raise ArgumentError("Too few arguments to kvtophys.") 1232 if kern.arch.startswith('arm'): 1233 print "{:#x}".format(KVToPhysARM(long(unsigned(kern.GetValueFromAddress(cmd_args[0], 'unsigned long'))))) 1234 elif kern.arch == 'x86_64': 1235 print "{:#x}".format(long(unsigned(kern.GetValueFromAddress(cmd_args[0], 'unsigned long'))) - unsigned(kern.globals.physmap_base)) 1236 1237@lldb_command('phystokv') 1238def PhysToKV(cmd_args=None): 1239 """ Translate a physical address to the corresponding static kernel virtual address. 1240 Assumes the physical address corresponds to managed DRAM. 1241 Syntax: (lldb) phystokv <physical address> 1242 """ 1243 if cmd_args == None or len(cmd_args) < 1: 1244 raise ArgumentError("Too few arguments to phystokv.") 1245 print "{:#x}".format(kern.PhysToKernelVirt(long(unsigned(kern.GetValueFromAddress(cmd_args[0], 'unsigned long'))))) 1246 1247def KVToPhysARM(addr): 1248 if kern.arch.startswith('arm64'): 1249 ptov_table = kern.globals.ptov_table 1250 for i in range(0, kern.globals.ptov_index): 1251 if (addr >= long(unsigned(ptov_table[i].va))) and (addr < (long(unsigned(ptov_table[i].va)) + long(unsigned(ptov_table[i].len)))): 1252 return (addr - long(unsigned(ptov_table[i].va)) + long(unsigned(ptov_table[i].pa))) 1253 return (addr - unsigned(kern.globals.gVirtBase) + unsigned(kern.globals.gPhysBase)) 1254 1255 1256def GetPtDesc(paddr): 1257 pn = (paddr - unsigned(kern.globals.vm_first_phys)) / kern.globals.page_size 1258 pvh = unsigned(kern.globals.pv_head_table[pn]) 1259 if kern.arch.startswith('arm64'): 1260 pvh = pvh | PVH_HIGH_FLAGS_ARM64 1261 else: 1262 pvh = pvh | PVH_HIGH_FLAGS_ARM32 1263 pvh_type = pvh & 0x3 1264 if pvh_type != 0x3: 1265 raise ValueError("PV head {:#x} does not correspond to a page-table descriptor".format(pvh)) 1266 ptd = kern.GetValueFromAddress(pvh & ~0x3, 'pt_desc_t *') 1267 return ptd 1268 1269def ShowPTEARM(pte, page_size, stage2 = False): 1270 """ Display vital information about an ARM page table entry 1271 pte: kernel virtual address of the PTE. Should be L3 PTE. May also work with L2 TTEs for certain devices. 1272 """ 1273 ptd = GetPtDesc(KVToPhysARM(pte)) 1274 pt_index = (pte % kern.globals.page_size) / page_size 1275 refcnt = ptd.ptd_info[pt_index].refcnt 1276 wiredcnt = ptd.ptd_info[pt_index].wiredcnt 1277 print "descriptor: {:#x} (refcnt: {:#x}, wiredcnt: {:#x})".format(ptd, refcnt, wiredcnt) 1278 1279 # PTDs used to describe IOMMU pages always have a refcnt of 0x8000/0x8001. 1280 is_iommu_pte = (refcnt & 0x8000) == 0x8000 1281 1282 # The pmap/iommu field is a union, so only print the correct one. 1283 if is_iommu_pte: 1284 iommu_desc_name = '{:s}'.format(dereference(dereference(ptd.iommu).desc).name) 1285 if unsigned(dereference(ptd.iommu).name) is not 0: 1286 iommu_desc_name += '/{:s}'.format(dereference(ptd.iommu).name) 1287 1288 print "iommu state: {:#x} ({:s})".format(ptd.iommu, iommu_desc_name) 1289 else: 1290 if ptd.pmap == kern.globals.kernel_pmap: 1291 pmap_str = "(kernel_pmap)" 1292 else: 1293 task = TaskForPmapHelper(ptd.pmap) 1294 pmap_str = "(User Task: {:s})".format("{:#x}".format(task) if task is not None else "<unknown>") 1295 print "pmap: {:#x} {:s}".format(ptd.pmap, pmap_str) 1296 1297 pte_pgoff = pte % page_size 1298 if kern.arch.startswith('arm64'): 1299 pte_pgoff = pte_pgoff / 8 1300 nttes = page_size / 8 1301 else: 1302 pte_pgoff = pte_pgoff / 4 1303 nttes = page_size / 4 1304 if ptd.ptd_info[pt_index].refcnt == 0x4000: 1305 level = 2 1306 granule = nttes * page_size 1307 else: 1308 level = 3 1309 granule = page_size 1310 print "maps {}: {:#x}".format("IPA" if stage2 else "VA", long(unsigned(ptd.va[pt_index])) + (pte_pgoff * granule)) 1311 pteval = long(unsigned(dereference(kern.GetValueFromAddress(unsigned(pte), 'pt_entry_t *')))) 1312 print "value: {:#x}".format(pteval) 1313 if kern.arch.startswith('arm64'): 1314 print "level: {:d}".format(level) 1315 PmapDecodeTTEARM64(pteval, level, stage2, is_iommu_pte) 1316 1317 elif kern.arch == 'arm': 1318 PmapDecodeTTEARM(pteval, 2, vSCRIPT) 1319 1320@lldb_command('showpte') 1321def ShowPTE(cmd_args=None): 1322 """ Display vital information about the page table entry at VA <pte> 1323 Syntax: (lldb) showpte <pte_va> [4k|16k|16k_s2] 1324 """ 1325 if cmd_args == None or len(cmd_args) < 1: 1326 raise ArgumentError("Too few arguments to showpte.") 1327 1328 if kern.arch == 'arm': 1329 ShowPTEARM(kern.GetValueFromAddress(cmd_args[0], 'unsigned long'), kern.globals.page_size) 1330 elif kern.arch.startswith('arm64'): 1331 pmap_pt_attr = kern.globals.native_pt_attr if len(cmd_args) < 2 else GetMemoryAttributesFromUser(cmd_args[1]) 1332 if pmap_pt_attr is None: 1333 raise ArgumentError("Invalid translation attribute type.") 1334 1335 stage2 = bool(pmap_pt_attr.stage2 if hasattr(pmap_pt_attr, 'stage2') else False) 1336 ShowPTEARM(kern.GetValueFromAddress(cmd_args[0], 'unsigned long'), pmap_pt_attr.pta_page_size, stage2) 1337 else: 1338 raise NotImplementedError("showpte does not support {0}".format(kern.arch)) 1339 1340def FindMappingAtLevelARM(pmap, tt, nttes, level, va, action): 1341 """ Perform the specified action for all valid mappings in an ARM translation table 1342 pmap: owner of the translation table 1343 tt: translation table or page table 1344 nttes: number of entries in tt 1345 level: translation table level, 1 or 2 1346 action: callback for each valid TTE 1347 """ 1348 for i in range(nttes): 1349 try: 1350 tte = tt[i] 1351 va_size = None 1352 if level == 1: 1353 if tte & 0x3 == 0x1: 1354 type = 'table' 1355 granule = 1024 1356 va_size = kern.globals.page_size * 256 1357 paddr = tte & 0xFFFFFC00 1358 elif tte & 0x3 == 0x2: 1359 type = 'block' 1360 if (tte & 0x40000) == 0x40000: 1361 granule = 1 << 24 1362 paddr = tte & 0xFF000000 1363 else: 1364 granule = 1 << 20 1365 paddr = tte & 0xFFF00000 1366 else: 1367 continue 1368 elif (tte & 0x3) == 0x1: 1369 type = 'entry' 1370 granule = 1 << 16 1371 paddr = tte & 0xFFFF0000 1372 elif (tte & 0x3) != 0: 1373 type = 'entry' 1374 granule = 1 << 12 1375 paddr = tte & 0xFFFFF000 1376 else: 1377 continue 1378 if va_size is None: 1379 va_size = granule 1380 mapped_va = va + (va_size * i) 1381 if action(pmap, level, type, addressof(tt[i]), paddr, mapped_va, granule): 1382 if level == 1 and (tte & 0x3) == 0x1: 1383 tt_next = kern.GetValueFromAddress(kern.PhysToKernelVirt(paddr), 'tt_entry_t *') 1384 FindMappingAtLevelARM(pmap, tt_next, granule / 4, level + 1, mapped_va, action) 1385 except Exception as exc: 1386 print "Unable to access tte {:#x}".format(unsigned(addressof(tt[i]))) 1387 1388def FindMappingAtLevelARM64(pmap, tt, nttes, level, va, action): 1389 """ Perform the specified action for all valid mappings in an ARM64 translation table 1390 pmap: owner of the translation table 1391 tt: translation table or page table 1392 nttes: number of entries in tt 1393 level: translation table level, 1 2 or 3 1394 action: callback for each valid TTE 1395 """ 1396 # Obtain pmap attributes 1397 pmap_pt_attr = pmap.pmap_pt_attr if hasattr(pmap, 'pmap_pt_attr') else kern.globals.native_pt_attr 1398 page_size = pmap_pt_attr.pta_page_size 1399 page_offset_mask = (page_size - 1) 1400 page_base_mask = ((1 << ARM64_VMADDR_BITS) - 1) & (~page_offset_mask) 1401 max_level = unsigned(pmap_pt_attr.pta_max_level) 1402 1403 for i in range(nttes): 1404 try: 1405 tte = tt[i] 1406 if tte & 0x1 == 0x0: 1407 continue 1408 1409 tt_next = None 1410 paddr = unsigned(tte) & unsigned(page_base_mask) 1411 1412 # Handle leaf entry 1413 if tte & 0x2 == 0x0 or level == max_level: 1414 type = 'block' if level < max_level else 'entry' 1415 granule = PmapBlockOffsetMaskARM64(page_size, level) + 1 1416 else: 1417 # Handle page table entry 1418 type = 'table' 1419 granule = page_size 1420 tt_next = kern.GetValueFromAddress(kern.PhysToKernelVirt(paddr), 'tt_entry_t *') 1421 1422 mapped_va = long(unsigned(va)) + ((PmapBlockOffsetMaskARM64(page_size, level) + 1) * i) 1423 if action(pmap, level, type, addressof(tt[i]), paddr, mapped_va, granule): 1424 if tt_next is not None: 1425 FindMappingAtLevelARM64(pmap, tt_next, granule / ARM64_TTE_SIZE, level + 1, mapped_va, action) 1426 1427 except Exception as exc: 1428 print "Unable to access tte {:#x}".format(unsigned(addressof(tt[i]))) 1429 1430def ScanPageTables(action, targetPmap=None): 1431 """ Perform the specified action for all valid mappings in all page tables, 1432 optionally restricted to a single pmap. 1433 pmap: pmap whose page table should be scanned. If None, all pmaps on system will be scanned. 1434 """ 1435 print "Scanning all available translation tables. This may take a long time..." 1436 def ScanPmap(pmap, action): 1437 if kern.arch.startswith('arm64'): 1438 # Obtain pmap attributes 1439 pmap_pt_attr = pmap.pmap_pt_attr if hasattr(pmap, 'pmap_pt_attr') else kern.globals.native_pt_attr 1440 granule = pmap_pt_attr.pta_page_size 1441 level = unsigned(pmap_pt_attr.pta_root_level) 1442 root_pgtable_num_ttes = (unsigned(pmap_pt_attr.pta_level_info[level].index_mask) >> \ 1443 unsigned(pmap_pt_attr.pta_level_info[level].shift)) + 1 1444 elif kern.arch == 'arm': 1445 granule = pmap.tte_index_max * 4 1446 1447 if action(pmap, pmap_pt_attr.pta_root_level, 'root', pmap.tte, unsigned(pmap.ttep), pmap.min, granule): 1448 if kern.arch.startswith('arm64'): 1449 FindMappingAtLevelARM64(pmap, pmap.tte, root_pgtable_num_ttes, level, pmap.min, action) 1450 elif kern.arch == 'arm': 1451 FindMappingAtLevelARM(pmap, pmap.tte, pmap.tte_index_max, 1, pmap.min, action) 1452 1453 if targetPmap is not None: 1454 ScanPmap(kern.GetValueFromAddress(targetPmap, 'pmap_t'), action) 1455 else: 1456 for pmap in IterateQueue(kern.globals.map_pmap_list, 'pmap_t', 'pmaps'): 1457 ScanPmap(pmap, action) 1458 1459@lldb_command('showallmappings') 1460def ShowAllMappings(cmd_args=None): 1461 """ Find and display all available mappings on the system for 1462 <physical_address>. Optionally only searches the pmap 1463 specified by [<pmap>] 1464 Syntax: (lldb) showallmappings <physical_address> [<pmap>] 1465 WARNING: this macro can take a long time (up to 30min.) to complete! 1466 """ 1467 if cmd_args == None or len(cmd_args) < 1: 1468 raise ArgumentError("Too few arguments to showallmappings.") 1469 if not kern.arch.startswith('arm'): 1470 raise NotImplementedError("showallmappings does not support {0}".format(kern.arch)) 1471 pa = kern.GetValueFromAddress(cmd_args[0], 'unsigned long') 1472 targetPmap = None 1473 if len(cmd_args) > 1: 1474 targetPmap = cmd_args[1] 1475 def printMatchedMapping(pmap, level, type, tte, paddr, va, granule): 1476 if paddr <= pa < (paddr + granule): 1477 print "pmap: {:#x}: L{:d} {:s} at {:#x}: [{:#x}, {:#x}), maps va {:#x}".format(pmap, level, type, unsigned(tte), paddr, paddr + granule, va) 1478 return True 1479 ScanPageTables(printMatchedMapping, targetPmap) 1480 1481@lldb_command('showptusage') 1482def ShowPTUsage(cmd_args=None): 1483 """ Display a summary of pagetable allocations for a given pmap. 1484 Syntax: (lldb) showptusage [<pmap>] 1485 WARNING: this macro can take a long time (> 1hr) to complete! 1486 """ 1487 if not kern.arch.startswith('arm'): 1488 raise NotImplementedError("showptusage does not support {0}".format(kern.arch)) 1489 targetPmap = None 1490 if len(cmd_args) > 0: 1491 targetPmap = cmd_args[0] 1492 lastPmap = [None] 1493 numTables = [0] 1494 numUnnested = [0] 1495 numPmaps = [0] 1496 def printValidTTE(pmap, level, type, tte, paddr, va, granule): 1497 unnested = "" 1498 nested_region_addr = long(unsigned(pmap.nested_region_addr)) 1499 nested_region_end = nested_region_addr + long(unsigned(pmap.nested_region_size)) 1500 if lastPmap[0] is None or (pmap != lastPmap[0]): 1501 lastPmap[0] = pmap 1502 numPmaps[0] = numPmaps[0] + 1 1503 print ("pmap {:#x}:".format(pmap)) 1504 if type == 'root': 1505 return True 1506 if (level == 2) and (va >= nested_region_addr) and (va < nested_region_end): 1507 ptd = GetPtDesc(paddr) 1508 if ptd.pmap != pmap: 1509 return False 1510 else: 1511 numUnnested[0] = numUnnested[0] + 1 1512 unnested = " (likely unnested)" 1513 numTables[0] = numTables[0] + 1 1514 print (" " * 4 * int(level)) + "L{:d} entry at {:#x}, maps {:#x}".format(level, unsigned(tte), va) + unnested 1515 if level == 2: 1516 return False 1517 else: 1518 return True 1519 ScanPageTables(printValidTTE, targetPmap) 1520 print("{:d} table(s), {:d} of them likely unnested, in {:d} pmap(s)".format(numTables[0], numUnnested[0], numPmaps[0])) 1521 1522def checkPVList(pmap, level, type, tte, paddr, va, granule): 1523 """ Checks an ARM physical-to-virtual mapping list for consistency errors. 1524 pmap: owner of the translation table 1525 level: translation table level. PV lists will only be checked for L2 (arm32) or L3 (arm64) tables. 1526 type: unused 1527 tte: KVA of PTE to check for presence in PV list. If None, presence check will be skipped. 1528 paddr: physical address whose PV list should be checked. Need not be page-aligned. 1529 granule: unused 1530 """ 1531 vm_first_phys = unsigned(kern.globals.vm_first_phys) 1532 vm_last_phys = unsigned(kern.globals.vm_last_phys) 1533 page_size = kern.globals.page_size 1534 if kern.arch.startswith('arm64'): 1535 page_offset_mask = (page_size - 1) 1536 page_base_mask = ((1 << ARM64_VMADDR_BITS) - 1) & (~page_offset_mask) 1537 paddr = paddr & page_base_mask 1538 max_level = 3 1539 pvh_set_bits = PVH_HIGH_FLAGS_ARM64 1540 elif kern.arch == 'arm': 1541 page_base_mask = 0xFFFFF000 1542 paddr = paddr & page_base_mask 1543 max_level = 2 1544 pvh_set_bits = PVH_HIGH_FLAGS_ARM32 1545 if level < max_level or paddr < vm_first_phys or paddr >= vm_last_phys: 1546 return True 1547 pn = (paddr - vm_first_phys) / page_size 1548 pvh = unsigned(kern.globals.pv_head_table[pn]) | pvh_set_bits 1549 pvh_type = pvh & 0x3 1550 if pmap is not None: 1551 pmap_str = "pmap: {:#x}: ".format(pmap) 1552 else: 1553 pmap_str = '' 1554 if tte is not None: 1555 tte_str = "pte {:#x} ({:#x}): ".format(unsigned(tte), paddr) 1556 else: 1557 tte_str = "paddr {:#x}: ".format(paddr) 1558 if pvh_type == 0 or pvh_type == 3: 1559 print "{:s}{:s}unexpected PVH type {:d}".format(pmap_str, tte_str, pvh_type) 1560 elif pvh_type == 2: 1561 ptep = pvh & ~0x3 1562 if tte is not None and ptep != unsigned(tte): 1563 print "{:s}{:s}PVH mismatch ({:#x})".format(pmap_str, tte_str, ptep) 1564 try: 1565 pte = long(unsigned(dereference(kern.GetValueFromAddress(ptep, 'pt_entry_t *')))) & page_base_mask 1566 if (pte != paddr): 1567 print "{:s}{:s}PVH {:#x} maps wrong page ({:#x}) ".format(pmap_str, tte_str, ptep, pte) 1568 except Exception as exc: 1569 print "{:s}{:s}Unable to read PVH {:#x}".format(pmap_str, tte_str, ptep) 1570 elif pvh_type == 1: 1571 pvep = pvh & ~0x3 1572 tte_match = False 1573 pve_ptep_idx = 0 1574 while pvep != 0: 1575 pve = kern.GetValueFromAddress(pvep, "pv_entry_t *") 1576 ptep = unsigned(pve.pve_ptep[pve_ptep_idx]) & ~0x3 1577 pve_ptep_idx += 1 1578 if pve_ptep_idx == 2: 1579 pve_ptep_idx = 0 1580 pvep = unsigned(pve.pve_next) 1581 if ptep == 0: 1582 continue 1583 if tte is not None and ptep == unsigned(tte): 1584 tte_match = True 1585 try: 1586 pte = long(unsigned(dereference(kern.GetValueFromAddress(ptep, 'pt_entry_t *')))) & page_base_mask 1587 if (pte != paddr): 1588 print "{:s}{:s}PVE {:#x} maps wrong page ({:#x}) ".format(pmap_str, tte_str, ptep, pte) 1589 except Exception as exc: 1590 print "{:s}{:s}Unable to read PVE {:#x}".format(pmap_str, tte_str, ptep) 1591 if tte is not None and not tte_match: 1592 print "{:s}{:s}not found in PV list".format(pmap_str, tte_str, paddr) 1593 return True 1594 1595@lldb_command('pv_check', 'P') 1596def PVCheck(cmd_args=None, cmd_options={}): 1597 """ Check the physical-to-virtual mapping for a given PTE or physical address 1598 Syntax: (lldb) pv_check <addr> [-p] 1599 -P : Interpret <addr> as a physical address rather than a PTE 1600 """ 1601 if cmd_args == None or len(cmd_args) < 1: 1602 raise ArgumentError("Too few arguments to pv_check.") 1603 if kern.arch == 'arm': 1604 level = 2 1605 elif kern.arch.startswith('arm64'): 1606 level = 3 1607 else: 1608 raise NotImplementedError("pv_check does not support {0}".format(kern.arch)) 1609 if "-P" in cmd_options: 1610 pte = None 1611 pa = long(unsigned(kern.GetValueFromAddress(cmd_args[0], "unsigned long"))) 1612 else: 1613 pte = kern.GetValueFromAddress(cmd_args[0], 'pt_entry_t *') 1614 pa = long(unsigned(dereference(pte))) 1615 checkPVList(None, level, None, pte, pa, 0, None) 1616 1617@lldb_command('check_pmaps') 1618def CheckPmapIntegrity(cmd_args=None): 1619 """ Performs a system-wide integrity check of all PTEs and associated PV lists. 1620 Optionally only checks the pmap specified by [<pmap>] 1621 Syntax: (lldb) check_pmaps [<pmap>] 1622 WARNING: this macro can take a HUGE amount of time (several hours) if you do not 1623 specify [pmap] to limit it to a single pmap. It will also give false positives 1624 for kernel_pmap, as we do not create PV entries for static kernel mappings on ARM. 1625 Use of this macro without the [<pmap>] argument is heavily discouraged. 1626 """ 1627 if not kern.arch.startswith('arm'): 1628 raise NotImplementedError("check_pmaps does not support {0}".format(kern.arch)) 1629 targetPmap = None 1630 if len(cmd_args) > 0: 1631 targetPmap = cmd_args[0] 1632 ScanPageTables(checkPVList, targetPmap) 1633 1634@lldb_command('pmapsforledger') 1635def PmapsForLedger(cmd_args=None): 1636 """ Find and display all pmaps currently using <ledger>. 1637 Syntax: (lldb) pmapsforledger <ledger> 1638 """ 1639 if cmd_args == None or len(cmd_args) < 1: 1640 raise ArgumentError("Too few arguments to pmapsforledger.") 1641 if not kern.arch.startswith('arm'): 1642 raise NotImplementedError("pmapsforledger does not support {0}".format(kern.arch)) 1643 ledger = kern.GetValueFromAddress(cmd_args[0], 'ledger_t') 1644 for pmap in IterateQueue(kern.globals.map_pmap_list, 'pmap_t', 'pmaps'): 1645 if pmap.ledger == ledger: 1646 print "pmap: {:#x}".format(pmap) 1647 1648 1649def IsValidPai(pai): 1650 """ Given an unsigned value, detect whether that value is a valid physical 1651 address index (PAI). It does this by first computing the last possible 1652 PAI and comparing the input to that. 1653 1654 All contemporary SoCs reserve the bottom part of the address space, so 1655 there shouldn't be any valid physical addresses between zero and the 1656 last PAI either. 1657 """ 1658 page_size = unsigned(kern.globals.page_size) 1659 vm_first_phys = unsigned(kern.globals.vm_first_phys) 1660 vm_last_phys = unsigned(kern.globals.vm_last_phys) 1661 1662 last_pai = (vm_last_phys - vm_first_phys) / page_size 1663 if (pai < 0) or (pai >= last_pai): 1664 return False 1665 1666 return True 1667 1668def ConvertPaiToPhysAddr(pai): 1669 """ Convert the given Physical Address Index (PAI) into a physical address. 1670 1671 If the input isn't a valid PAI (it's most likely already a physical 1672 address), then just return back the input unchanged. 1673 """ 1674 pa = pai 1675 1676 # If the value is a valid PAI, then convert it into a physical address. 1677 if IsValidPai(pai): 1678 pa = (pai * unsigned(kern.globals.page_size)) + unsigned(kern.globals.vm_first_phys) 1679 1680 return pa 1681 1682def ConvertPhysAddrToPai(pa): 1683 """ Convert the given physical address into a Physical Address Index (PAI). 1684 1685 If the input is already a valid PAI, then just return back the input 1686 unchanged. 1687 """ 1688 vm_first_phys = unsigned(kern.globals.vm_first_phys) 1689 vm_last_phys = unsigned(kern.globals.vm_last_phys) 1690 pai = pa 1691 1692 if not IsValidPai(pa) and (pa < vm_first_phys or pa >= vm_last_phys): 1693 raise ArgumentError("{:#x} is neither a valid PAI nor a kernel-managed address: [{:#x}, {:#x})".format(pa, vm_first_phys, vm_last_phys)) 1694 elif not IsValidPai(pa): 1695 # If the value isn't already a valid PAI, then convert it into one. 1696 pai = (pa - vm_first_phys) / unsigned(kern.globals.page_size) 1697 1698 return pai 1699 1700@lldb_command('pmappaindex') 1701def PmapPaIndex(cmd_args=None): 1702 """ Display both a physical address and physical address index (PAI) when 1703 provided with only one of those values. 1704 1705 Syntax: (lldb) pmappaindex <physical address | PAI> 1706 1707 NOTE: This macro will throw an exception if the input isn't a valid PAI 1708 and is also not a kernel-managed physical address. 1709 """ 1710 if (cmd_args == None) or (len(cmd_args) < 1): 1711 raise ArgumentError("Too few arguments to pmappaindex.") 1712 1713 if not kern.arch.startswith('arm'): 1714 raise NotImplementedError("pmappaindex is only supported on ARM devices.") 1715 1716 value = kern.GetValueFromAddress(cmd_args[0], 'unsigned long') 1717 pai = value 1718 phys_addr = value 1719 1720 if IsValidPai(value): 1721 # Input is a PAI, calculate the physical address. 1722 phys_addr = ConvertPaiToPhysAddr(value) 1723 else: 1724 # Input is a physical address, calculate the PAI 1725 pai = ConvertPhysAddrToPai(value) 1726 1727 print "Physical Address: {:#x}".format(phys_addr) 1728 print "PAI: {:d}".format(pai) 1729