7 def ReadPhysInt(phys_addr
, bitsize
= 64, cpuval
= None):
8 """ Read a physical memory data based on address.
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)
14 int - int value read from memory. in case of failure 0xBAD10AD is returned.
16 if "kdp" == GetConnectionProtocol():
17 return KDPReadPhysMEM(phys_addr
, bitsize
)
19 #NO KDP. Attempt to use physical memory
20 paddr_in_kva
= kern
.PhysToKernelVirt(long(phys_addr
))
23 return kern
.GetValueFromAddress(paddr_in_kva
, 'uint64_t *').GetSBValue().Dereference().GetValueAsUnsigned()
25 return kern
.GetValueFromAddress(paddr_in_kva
, 'uint32_t *').GetSBValue().Dereference().GetValueAsUnsigned()
27 return kern
.GetValueFromAddress(paddr_in_kva
, 'uint16_t *').GetSBValue().Dereference().GetValueAsUnsigned()
29 return kern
.GetValueFromAddress(paddr_in_kva
, 'uint8_t *').GetSBValue().Dereference().GetValueAsUnsigned()
32 @lldb_command('readphys')
33 def 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>
39 address: 1234 or 0x1234
41 if cmd_args
== None or len(cmd_args
) < 2:
42 print "Insufficient arguments.", ReadPhys
.__doc
__
45 nbits
= ArgumentStringToInt(cmd_args
[0])
46 phys_addr
= ArgumentStringToInt(cmd_args
[1])
47 print "{0: <#x}".format(ReadPhysInt(phys_addr
, nbits
))
50 lldb_alias('readphys8', 'readphys 8 ')
51 lldb_alias('readphys16', 'readphys 16 ')
52 lldb_alias('readphys32', 'readphys 32 ')
53 lldb_alias('readphys64', 'readphys 64 ')
55 def KDPReadPhysMEM(address
, bits
):
56 """ Setup the state for READPHYSMEM64 commands for reading data via kdp
58 address : int - address where to read the data from
59 bits : int - number of bits in the intval (8/16/32/64)
61 int: read value from memory.
62 0xBAD10AD: if failed to read data.
65 if "kdp" != GetConnectionProtocol():
66 print "Target is not connected over kdp. Nothing to do here."
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)
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
)
79 if ret_obj
.Succeeded():
80 value
= ret_obj
.GetOutput()
95 retval
= struct
.unpack(unpack_fmt
, struct
.pack(pack_fmt
, int(value
[-((bits
/4)+1):], 16)))[0]
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
))
102 if not WriteInt32ToMemoryAddress(0, input_address
):
105 kdp_pkt_size
= GetType('kdp_readphysmem64_req_t').GetByteSize()
106 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
109 data_addr
= int(addressof(kern
.globals.manual_pkt
))
110 pkt
= kern
.GetValueFromAddress(data_addr
, 'kdp_readphysmem64_req_t *')
112 header_value
=GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_READPHYSMEM64'), length
=kdp_pkt_size
)
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
)))
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
))
124 retval
= kern
.GetValueFromAddress(data_address
, 'uint64_t *').GetSBValue().Dereference().GetValueAsUnsigned()
126 retval
= kern
.GetValueFromAddress(data_address
, 'uint32_t *').GetSBValue().Dereference().GetValueAsUnsigned()
128 retval
= kern
.GetValueFromAddress(data_address
, 'uint16_t *').GetSBValue().Dereference().GetValueAsUnsigned()
130 retval
= kern
.GetValueFromAddress(data_address
, 'uint8_t *').GetSBValue().Dereference().GetValueAsUnsigned()
135 def KDPWritePhysMEM(address
, intval
, bits
):
136 """ Setup the state for WRITEPHYSMEM64 commands for saving data in kdp
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)
142 boolean: True if the write succeeded.
144 if "kdp" != GetConnectionProtocol():
145 print "Target is not connected over kdp. Nothing to do here."
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]
166 data_val
= struct
.unpack(unpack_fmt
, struct
.pack(pack_fmt
, intval
))[0]
168 packet
= "{0:016x}{1:08x}{2:04x}{3:016x}".format(addr_for_kdp
, byte_count
, 0x0, data_val
)
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
)
174 if ret_obj
.Succeeded():
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
):
186 kdp_pkt_size
= GetType('kdp_writephysmem64_req_t').GetByteSize() + (bits
/ 8)
187 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
190 data_addr
= int(addressof(kern
.globals.manual_pkt
))
191 pkt
= kern
.GetValueFromAddress(data_addr
, 'kdp_writephysmem64_req_t *')
193 header_value
=GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_WRITEPHYSMEM64'), length
=kdp_pkt_size
)
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
)))
202 if not WriteInt8ToMemoryAddress(intval
, int(addressof(pkt
.data
))):
205 if not WriteInt16ToMemoryAddress(intval
, int(addressof(pkt
.data
))):
208 if not WriteInt32ToMemoryAddress(intval
, int(addressof(pkt
.data
))):
211 if not WriteInt64ToMemoryAddress(intval
, int(addressof(pkt
.data
))):
213 if WriteInt32ToMemoryAddress(1, input_address
):
218 def WritePhysInt(phys_addr
, int_val
, bitsize
= 64):
219 """ Write and integer value in a physical memory data based on address.
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
225 bool - True if write was successful.
227 if "kdp" == GetConnectionProtocol():
228 if not KDPWritePhysMEM(phys_addr
, int_val
, bitsize
):
229 print "Failed to write via KDP."
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()
236 @lldb_command('writephys')
237 def 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>
243 address: 1234 or 0x1234
244 value: int value to be written
245 ex. (lldb)writephys 16 0x12345abcd 0x25
247 if cmd_args
== None or len(cmd_args
) < 3:
248 print "Invalid arguments.", WritePhys
.__doc
__
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
)
256 lldb_alias('writephys8', 'writephys 8 ')
257 lldb_alias('writephys16', 'writephys 16 ')
258 lldb_alias('writephys32', 'writephys 32 ')
259 lldb_alias('writephys64', 'writephys 64 ')
262 def _PT_Step(paddr
, index
, verbose_level
= vSCRIPT
):
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
273 pt_valid: 1 if $kgm_pt_paddr is valid, 0 if the walk
275 pt_large: 1 if kgm_pt_paddr is a page frame address
276 of a large page and not another page table entry
278 entry_addr
= paddr
+ (8 * index
)
279 entry
= ReadPhysInt(entry_addr
, 64, xnudefines
.lcpu_self
)
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)
290 if verbose_level
< vSCRIPT
:
294 pt_paddr
= entry
& paddr_mask
295 if entry
& (0x1 <<7):
297 pt_paddr
= entry
& paddr_large_mask
299 out_string
+= "{0: <#020x}:\n\t{1:#020x}\n\t".format(entry_addr
, entry
)
301 out_string
+= " valid"
302 pt_paddr
= entry
& paddr_mask
305 out_string
+= " invalid"
308 if entry
& (0x1 << 62):
309 out_string
+= " compressed"
310 #Stop decoding other bits
312 if entry
& (0x1 << 1):
313 out_string
+= " writable"
315 out_string
+= " read-only"
317 if entry
& (0x1 << 2):
318 out_string
+= " user"
320 out_string
+= " supervisor"
322 if entry
& (0x1 << 3):
325 if entry
& (0x1 << 4):
328 if entry
& (0x1 << 5):
329 out_string
+= " accessed"
331 if entry
& (0x1 << 6):
332 out_string
+= " dirty"
334 if entry
& (0x1 << 7):
335 out_string
+= " large"
340 if entry
& (0x1 << 8):
341 out_string
+= " global"
343 if entry
& (0x3 << 9):
344 out_string
+= " avail:{0:x}".format((entry
>> 9) & 0x3)
346 if entry
& (0x1 << 63):
347 out_string
+= " noexec"
349 return (pt_paddr
, pt_valid
, pt_large
)
351 def _PT_StepEPT(paddr
, index
, verbose_level
= vSCRIPT
):
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
362 pt_valid: 1 if $kgm_pt_paddr is valid, 0 if the walk
364 pt_large: 1 if kgm_pt_paddr is a page frame address
365 of a large page and not another page table entry
367 entry_addr
= paddr
+ (8 * index
)
368 entry
= ReadPhysInt(entry_addr
, 64, xnudefines
.lcpu_self
)
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)
379 if verbose_level
< vSCRIPT
:
383 pt_paddr
= entry
& paddr_mask
384 if entry
& (0x1 <<7):
386 pt_paddr
= entry
& paddr_large_mask
388 out_string
+= "{0: <#020x}:\n\t{1:#020x}\n\t".format(entry_addr
, entry
)
390 out_string
+= "valid"
391 pt_paddr
= entry
& paddr_mask
394 out_string
+= "invalid"
397 if entry
& (0x1 << 62):
398 out_string
+= " compressed"
399 #Stop decoding other bits
402 out_string
+= " readable"
404 out_string
+= " no read"
405 if entry
& (0x1 << 1):
406 out_string
+= " writable"
408 out_string
+= " no write"
410 if entry
& (0x1 << 2):
411 out_string
+= " executable"
413 out_string
+= " no exec"
417 out_string
+= " cache-WB"
419 out_string
+= " cache-WP"
421 out_string
+= " cache-WT"
423 out_string
+= " cache-WC"
425 out_string
+= " cache-NC"
427 if (entry
& 0x40) == 0x40:
428 out_string
+= " Ignore-PTA"
430 if (entry
& 0x100) == 0x100:
431 out_string
+= " accessed"
433 if (entry
& 0x200) == 0x200:
434 out_string
+= " dirty"
436 if entry
& (0x1 << 7):
437 out_string
+= " large"
442 return (pt_paddr
, pt_valid
, pt_large
)
444 def _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
449 pt_paddr
= unsigned(pmap_addr_val
)
450 pt_valid
= (unsigned(pmap_addr_val
) != 0)
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
)
460 (pt_paddr
, pt_valid
, pt_large
) = _PT_Step(pt_paddr
, pt_index
, verbose_level
)
462 (pt_paddr
, pt_valid
, pt_large
) = _PT_StepEPT(pt_paddr
, pt_index
, verbose_level
)
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
)
470 (pt_paddr
, pt_valid
, pt_large
) = _PT_Step(pt_paddr
, pt_index
, verbose_level
)
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
)
480 (pt_paddr
, pt_valid
, pt_large
) = _PT_Step(pt_paddr
, pt_index
, verbose_level
)
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
)
490 (pt_paddr
, pt_valid
, pt_large
) = _PT_Step(pt_paddr
, pt_index
, verbose_level
)
492 (pt_paddr
, pt_valid
, pt_large
) = _PT_StepEPT(pt_paddr
, pt_index
, verbose_level
)
494 paddr_isvalid
= False
496 paddr
= pt_paddr
+ pframe_offset
499 if verbose_level
> vHUMAN
:
501 pvalue
= ReadPhysInt(paddr
, 32, xnudefines
.lcpu_self
)
502 print "phys {0: <#020x}: {1: <#020x}".format(paddr
, pvalue
)
504 print "no translation"
508 def 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
516 if level
== 1 and (tte
& 0x3) == 0x2:
517 if verbose_level
< vSCRIPT
:
520 #bit [1:0] evaluated in PmapWalkARM
522 b_bit
= (tte
& 0x4) >> 2
524 c_bit
= (tte
& 0x8) >> 3
527 out_string
+= "no-execute"
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) )
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
]
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,
551 out_string
+= " shareable"
553 out_string
+= " not-shareable"
556 out_string
+= " not-global"
558 out_string
+= " global"
559 # Supersection bit 18
561 out_string
+= " supersection"
563 out_string
+= " section"
566 out_string
+= " no-secure"
568 out_string
+= " secure"
570 elif level
== 1 and (tte
& 0x3) == 0x1:
572 if verbose_level
>= vSCRIPT
:
573 # bit [1:0] evaluated in PmapWalkARM
576 out_string
+= ' no-secure'
578 out_string
+= ' secure'
580 out_string
+= " domain({:d})".format(((tte
& 0x1e0) >> 5))
582 out_string
+= " imp({:d})".format( ((tte
& 0x200) >> 9))
587 if verbose_level
>= vSCRIPT
:
588 if (pte
& 0x3) == 0x0:
589 out_string
+= " invalid"
591 if (pte
& 0x3) == 0x1:
592 out_string
+= " large"
594 if pte
& 0x8000 == 0x8000:
595 out_string
+= " no-execute"
597 out_string
+= " execute"
599 out_string
+= " small"
601 if (pte
& 0x1) == 0x01:
602 out_string
+= " no-execute"
604 out_string
+= " execute"
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
]
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)
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,
627 out_string
+= " shareable"
629 out_string
+= " not-shareable"
633 out_string
+= " not-global"
635 out_string
+= " global"
640 def _PmapWalkARMLevel1Section(tte
, vaddr
, verbose_level
= vSCRIPT
):
642 #Supersection or just section?
643 if (tte
& 0x40000) == 0x40000:
644 paddr
= ( (tte
& 0xFF000000) |
(vaddr
& 0x00FFFFFF) )
646 paddr
= ( (tte
& 0xFFF00000) |
(vaddr
& 0x000FFFFF) )
648 if verbose_level
>= vSCRIPT
:
649 print "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte
), tte
),
651 PmapDecodeTTEARM(tte
, 1, verbose_level
)
657 def _PmapWalkARMLevel2(tte
, vaddr
, verbose_level
= vSCRIPT
):
658 """ Pmap walk the level 2 tte.
662 returns: str - description of the tte + additional informaiton based on verbose_level
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
]
671 paddr
= (unsigned(pte
) & 0xFFFFF000) |
(vaddr
& 0xFFF)
673 if verbose_level
>= vSCRIPT
:
674 print "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte
), tte
),
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
:
681 tmp
= pte_base_val
[i
]
682 print "{0: <#020x}:\t{1: <#020x}".format(addressof(tmp
), unsigned(tmp
))
684 if verbose_level
>= vSCRIPT
:
685 print " {0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(pte
), unsigned(pte
)),
687 PmapDecodeTTEARM(pte
, 2, verbose_level
)
690 #end of level 2 walking of arm
693 def PmapWalkARM(pmap
, vaddr
, verbose_level
= vHUMAN
):
694 """ Pmap walking for ARM kernel.
696 pmapval: core.value - representing pmap_t in kernel
697 vaddr: int - integer representing virtual address to walk
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
)
719 if verbose_level
>= vSCRIPT
:
720 print "Invalid First-Level Translation Table Entry: {0: #020x}".format(tte
)
722 if verbose_level
>= vHUMAN
:
724 print "Translation of {:#x} is {:#x}.".format(vaddr
, paddr
)
726 print "(no translation)"
730 def PmapWalkX86_64(pmapval
, vaddr
, verbose_level
= vSCRIPT
):
732 params: pmapval - core.value representing pmap_t in kernel
733 vaddr: int - int representing virtual address to walk
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'])
740 if verbose_level
> vHUMAN
:
741 print "Using EPT pmap from pm_eptp\n"
742 return _PmapL4Walk(pmapval
.pm_eptp
, vaddr
, 1, config
['verbosity'])
744 def assert_64bit(val
):
749 ARM64_VMADDR_BITS
= 48
751 def 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
756 def PmapBlockBaseMaskARM64(page_size
, level
):
757 assert level
>= 0 and level
<= 3
758 return ((1 << ARM64_VMADDR_BITS
) - 1) & ~
PmapBlockOffsetMaskARM64(page_size
, level
)
760 def PmapDecodeTTEARM64(tte
, level
, stage2
= 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.
766 assert(type(level
) == int)
773 if (tte
& 0x2 == 0x2) and (level
!= 0x3):
774 print "Type = Table pointer."
775 print "Table addr = {:#x}.".format(tte
& 0xfffffffff000)
778 print "PXN = {:#x}.".format((tte
>> 59) & 0x1)
779 print "XN = {:#x}.".format((tte
>> 60) & 0x1)
780 print "AP = {:#x}.".format((tte
>> 61) & 0x3)
781 print "NS = {:#x}.".format(tte
>> 63)
783 print "Type = Block."
786 print "S2 MemAttr = {:#x}.".format((tte
>> 2) & 0xf)
788 print "AttrIdx = {:#x}.".format((tte
>> 2) & 0x7)
789 print "NS = {:#x}.".format((tte
>> 5) & 0x1)
792 print "S2AP = {:#x}.".format((tte
>> 6) & 0x3)
794 print "AP = {:#x}.".format((tte
>> 6) & 0x3)
796 print "SH = {:#x}.".format((tte
>> 8) & 0x3)
797 print "AF = {:#x}.".format((tte
>> 10) & 0x1)
800 print "nG = {:#x}.".format((tte
>> 11) & 0x1)
802 print "HINT = {:#x}.".format((tte
>> 52) & 0x1)
805 print "S2XN = {:#x}.".format((tte
>> 53) & 0x3)
807 print "PXN = {:#x}.".format((tte
>> 53) & 0x1)
808 print "XN = {:#x}.".format((tte
>> 54) & 0x1)
810 print "SW Use = {:#x}.".format((tte
>> 55) & 0xf)
814 def PmapTTnIndexARM64(vaddr
, pmap_pt_attr
):
815 pta_max_level
= unsigned(pmap_pt_attr
.pta_max_level
)
818 for i
in range(pta_max_level
+ 1):
819 tt_index
.append((vaddr
& unsigned(pmap_pt_attr
.pta_level_info
[i
].index_mask
)) \
820 >> unsigned(pmap_pt_attr
.pta_level_info
[i
].shift
))
824 def PmapWalkARM64(pmap_pt_attr
, root_tte
, vaddr
, verbose_level
= vHUMAN
):
825 assert(type(vaddr
) in (long, int))
827 assert_64bit(root_tte
)
829 # Obtain pmap attributes
830 page_size
= pmap_pt_attr
.pta_page_size
831 page_offset_mask
= (page_size
- 1)
832 page_base_mask
= ((1 << ARM64_VMADDR_BITS
) - 1) & (~page_offset_mask
)
833 tt_index
= PmapTTnIndexARM64(vaddr
, pmap_pt_attr
)
834 stage2
= bool(pmap_pt_attr
.stage2
if hasattr(pmap_pt_attr
, 'stage2') else False)
836 # The pmap starts at a page table level that is defined by register
837 # values; the root level can be obtained from the attributes structure
838 level
= unsigned(pmap_pt_attr
.pta_root_level
)
840 root_tt_index
= tt_index
[level
]
841 root_pgtable_num_ttes
= (unsigned(pmap_pt_attr
.pta_level_info
[level
].index_mask
) >> \
842 unsigned(pmap_pt_attr
.pta_level_info
[level
].shift
)) + 1
843 tte
= long(unsigned(root_tte
[root_tt_index
]))
845 # Walk the page tables
847 max_level
= unsigned(pmap_pt_attr
.pta_max_level
)
849 while (level
<= max_level
):
850 if verbose_level
>= vSCRIPT
:
851 print "L{} entry: {:#x}".format(level
, tte
)
852 if verbose_level
>= vDETAIL
:
853 PmapDecodeTTEARM64(tte
, level
, stage2
)
856 if verbose_level
>= vHUMAN
:
857 print "L{} entry invalid: {:#x}\n".format(level
, tte
)
861 if tte
& 0x2 == 0x0 or level
== max_level
:
862 base_mask
= page_base_mask
if level
== max_level
else PmapBlockBaseMaskARM64(page_size
, level
)
863 offset_mask
= page_offset_mask
if level
== max_level
else PmapBlockOffsetMaskARM64(page_size
, level
)
864 paddr
= tte
& base_mask
865 paddr
= paddr |
(vaddr
& offset_mask
)
867 if level
!= max_level
:
868 print "phys: {:#x}".format(paddr
)
872 # Handle page table entry
873 next_phys
= (tte
& page_base_mask
) + (ARM64_TTE_SIZE
* tt_index
[level
+ 1])
874 assert(type(next_phys
) == long)
876 next_virt
= kern
.PhysToKernelVirt(next_phys
)
877 assert(type(next_virt
) == long)
879 if verbose_level
>= vDETAIL
:
880 print "L{} physical address: {:#x}. L{} virtual address: {:#x}".format(level
+ 1, next_phys
, level
+ 1, next_virt
)
882 ttep
= kern
.GetValueFromAddress(next_virt
, "tt_entry_t*")
883 tte
= long(unsigned(dereference(ttep
)))
884 assert(type(tte
) == long)
886 # We've parsed one level, so go to the next level
890 if verbose_level
>= vHUMAN
:
892 print "Translation of {:#x} is {:#x}.".format(vaddr
, paddr
)
894 print "(no translation)"
898 def PmapWalk(pmap
, vaddr
, verbose_level
= vHUMAN
):
899 if kern
.arch
== 'x86_64':
900 return PmapWalkX86_64(pmap
, vaddr
, verbose_level
)
901 elif kern
.arch
== 'arm':
902 return PmapWalkARM(pmap
, vaddr
, verbose_level
)
903 elif kern
.arch
.startswith('arm64'):
904 # Obtain pmap attributes from pmap structure
905 pmap_pt_attr
= pmap
.pmap_pt_attr
if hasattr(pmap
, 'pmap_pt_attr') else kern
.globals.native_pt_attr
906 return PmapWalkARM64(pmap_pt_attr
, pmap
.tte
, vaddr
, verbose_level
)
908 raise NotImplementedError("PmapWalk does not support {0}".format(kern
.arch
))
910 @lldb_command('pmap_walk')
911 def PmapWalkHelper(cmd_args
=None):
912 """ Perform a page-table walk in <pmap> for <virtual_address>.
913 Syntax: (lldb) pmap_walk <pmap> <virtual_address> [-v] [-e]
914 Multiple -v's can be specified for increased verbosity
916 if cmd_args
== None or len(cmd_args
) < 2:
917 raise ArgumentError("Too few arguments to pmap_walk.")
919 pmap
= kern
.GetValueAsType(cmd_args
[0], 'pmap_t')
920 addr
= ArgumentStringToInt(cmd_args
[1])
921 PmapWalk(pmap
, addr
, config
['verbosity'])
924 def GetMemoryAttributesFromUser(requested_type
):
926 '4k' : kern
.globals.pmap_pt_attr_4k
,
927 '16k' : kern
.globals.pmap_pt_attr_16k
,
928 '16k_s2' : kern
.globals.pmap_pt_attr_16k_stage2
if hasattr(kern
.globals, 'pmap_pt_attr_16k_stage2') else None,
931 requested_type
= requested_type
.lower()
932 if requested_type
not in pmap_attr_dict
:
935 return pmap_attr_dict
[requested_type
]
937 @lldb_command('ttep_walk')
938 def TTEPWalkPHelper(cmd_args
=None):
939 """ Perform a page-table walk in <root_ttep> for <virtual_address>.
940 Syntax: (lldb) ttep_walk <root_ttep> <virtual_address> [4k|16k|16k_s2] [-v] [-e]
941 Multiple -v's can be specified for increased verbosity
943 if cmd_args
== None or len(cmd_args
) < 2:
944 raise ArgumentError("Too few arguments to ttep_walk.")
946 if not kern
.arch
.startswith('arm64'):
947 raise NotImplementedError("ttep_walk does not support {0}".format(kern
.arch
))
949 tte
= kern
.GetValueFromAddress(kern
.PhysToKernelVirt(ArgumentStringToInt(cmd_args
[0])), 'unsigned long *')
950 addr
= ArgumentStringToInt(cmd_args
[1])
952 pmap_pt_attr
= kern
.globals.native_pt_attr
if len(cmd_args
) < 3 else GetMemoryAttributesFromUser(cmd_args
[2])
953 if pmap_pt_attr
is None:
954 raise ArgumentError("Invalid translation attribute type.")
956 return PmapWalkARM64(pmap_pt_attr
, tte
, addr
, config
['verbosity'])
958 @lldb_command('decode_tte')
959 def DecodeTTE(cmd_args
=None):
960 """ Decode the bits in the TTE/PTE value specified <tte_val> for translation level <level> and stage [s1|s2]
961 Syntax: (lldb) decode_tte <tte_val> <level> [s1|s2]
963 if cmd_args
== None or len(cmd_args
) < 2:
964 raise ArgumentError("Too few arguments to decode_tte.")
965 if len(cmd_args
) > 2 and cmd_args
[2] not in ["s1", "s2"]:
966 raise ArgumentError("{} is not a valid stage of translation.".format(cmd_args
[2]))
967 if kern
.arch
== 'arm':
968 PmapDecodeTTEARM(kern
.GetValueFromAddress(cmd_args
[0], "unsigned long"), ArgumentStringToInt(cmd_args
[1]), vSCRIPT
)
969 elif kern
.arch
.startswith('arm64'):
970 stage2
= True if len(cmd_args
) > 2 and cmd_args
[2] == "s2" else False
971 PmapDecodeTTEARM64(ArgumentStringToInt(cmd_args
[0]), ArgumentStringToInt(cmd_args
[1]), stage2
)
973 raise NotImplementedError("decode_tte does not support {0}".format(kern
.arch
))
976 PVH_HIGH_FLAGS_ARM64
= (1 << 62) |
(1 << 61) |
(1 << 60) |
(1 << 59)
977 PVH_HIGH_FLAGS_ARM32
= (1 << 31)
980 """ Walk a physical-to-virtual reverse mapping list maintained by the arm pmap
981 pa: physical address (NOT page number). Does not need to be page-aligned
983 vm_first_phys
= unsigned(kern
.globals.vm_first_phys
)
984 vm_last_phys
= unsigned(kern
.globals.vm_last_phys
)
985 if pa
< vm_first_phys
or pa
>= vm_last_phys
:
986 raise ArgumentError("PA {:#x} is outside range of managed physical addresses: [{:#x}, {:#x})".format(pa
, vm_first_phys
, vm_last_phys
))
987 page_size
= kern
.globals.page_size
988 pn
= (pa
- unsigned(kern
.globals.vm_first_phys
)) / page_size
989 pvh
= unsigned(kern
.globals.pv_head_table
[pn
])
991 print "PVH raw value: ({:#x})".format(pvh
)
992 if kern
.arch
.startswith('arm64'):
994 iommu_table_flag
= 1 << 63
995 pvh
= pvh | PVH_HIGH_FLAGS_ARM64
999 pvh
= pvh | PVH_HIGH_FLAGS_ARM32
1001 print "PVH type: NULL"
1004 print "PVH type: page-table descriptor ({:#x})".format(pvh
& ~
0x3)
1009 print "PVH type: single PTE"
1010 if ptep
& iommu_flag
:
1011 ptep
= ptep
& ~iommu_flag
1012 if ptep
& iommu_table_flag
:
1013 pte_str
= ' (IOMMU table), entry'
1015 pte_str
= ' (IOMMU state), descriptor'
1016 ptep
= ptep | iommu_table_flag
1017 print "PTE {:#x}{:s}: {:#x}".format(ptep
, pte_str
, dereference(kern
.GetValueFromAddress(ptep
, 'pt_entry_t *')))
1020 print "PVH type: PTE list"
1022 pve
= kern
.GetValueFromAddress(pvep
, "pv_entry_t *")
1023 if unsigned(pve
.pve_next
) & 0x1:
1024 pve_str
= ' (alt acct) '
1028 pvep
= unsigned(pve
.pve_next
) & ~
0x1
1029 ptep
= unsigned(pve
.pve_ptep
) & ~
0x3
1030 if ptep
& iommu_flag
:
1031 ptep
= ptep
& ~iommu_flag
1032 if ptep
& iommu_table_flag
:
1033 pve_str
= ' (IOMMU table), entry'
1035 pve_str
= ' (IOMMU state), descriptor'
1036 ptep
= ptep | iommu_table_flag
1038 print "PVE {:#x}, PTE {:#x}{:s}: {:#x}".format(current_pvep
, ptep
, pve_str
, dereference(kern
.GetValueFromAddress(ptep
, 'pt_entry_t *')))
1040 print "PVE {:#x}, PTE {:#x}{:s}: <unavailable>".format(current_pvep
, ptep
, pve_str
)
1042 @lldb_command('pv_walk')
1043 def PVWalk(cmd_args
=None):
1044 """ Show mappings for <physical_address> tracked in the PV list.
1045 Syntax: (lldb) pv_walk <physical_address>
1047 if cmd_args
== None or len(cmd_args
) < 1:
1048 raise ArgumentError("Too few arguments to pv_walk.")
1049 if not kern
.arch
.startswith('arm'):
1050 raise NotImplementedError("pv_walk does not support {0}".format(kern
.arch
))
1051 PVWalkARM(kern
.GetValueFromAddress(cmd_args
[0], 'unsigned long'))
1053 @lldb_command('kvtophys')
1054 def KVToPhys(cmd_args
=None):
1055 """ Translate a kernel virtual address to the corresponding physical address.
1056 Assumes the virtual address falls within the kernel static region.
1057 Syntax: (lldb) kvtophys <kernel virtual address>
1059 if cmd_args
== None or len(cmd_args
) < 1:
1060 raise ArgumentError("Too few arguments to kvtophys.")
1061 if kern
.arch
.startswith('arm'):
1062 print "{:#x}".format(KVToPhysARM(long(unsigned(kern
.GetValueFromAddress(cmd_args
[0], 'unsigned long')))))
1063 elif kern
.arch
== 'x86_64':
1064 print "{:#x}".format(long(unsigned(kern
.GetValueFromAddress(cmd_args
[0], 'unsigned long'))) - unsigned(kern
.globals.physmap_base
))
1066 @lldb_command('phystokv')
1067 def PhysToKV(cmd_args
=None):
1068 """ Translate a physical address to the corresponding static kernel virtual address.
1069 Assumes the physical address corresponds to managed DRAM.
1070 Syntax: (lldb) phystokv <physical address>
1072 if cmd_args
== None or len(cmd_args
) < 1:
1073 raise ArgumentError("Too few arguments to phystokv.")
1074 print "{:#x}".format(kern
.PhysToKernelVirt(long(unsigned(kern
.GetValueFromAddress(cmd_args
[0], 'unsigned long')))))
1076 def KVToPhysARM(addr
):
1077 if kern
.arch
.startswith('arm64'):
1078 ptov_table
= kern
.globals.ptov_table
1079 for i
in range(0, kern
.globals.ptov_index
):
1080 if (addr
>= long(unsigned(ptov_table
[i
].va
))) and (addr
< (long(unsigned(ptov_table
[i
].va
)) + long(unsigned(ptov_table
[i
].len)))):
1081 return (addr
- long(unsigned(ptov_table
[i
].va
)) + long(unsigned(ptov_table
[i
].pa
)))
1082 return (addr
- unsigned(kern
.globals.gVirtBase
) + unsigned(kern
.globals.gPhysBase
))
1085 def GetPtDesc(paddr
):
1086 pn
= (paddr
- unsigned(kern
.globals.vm_first_phys
)) / kern
.globals.page_size
1087 pvh
= unsigned(kern
.globals.pv_head_table
[pn
])
1088 if kern
.arch
.startswith('arm64'):
1089 pvh
= pvh | PVH_HIGH_FLAGS_ARM64
1091 pvh
= pvh | PVH_HIGH_FLAGS_ARM32
1092 pvh_type
= pvh
& 0x3
1094 raise ValueError("PV head {:#x} does not correspond to a page-table descriptor".format(pvh
))
1095 ptd
= kern
.GetValueFromAddress(pvh
& ~
0x3, 'pt_desc_t *')
1098 def ShowPTEARM(pte
, page_size
, stage2
= False):
1099 """ Display vital information about an ARM page table entry
1100 pte: kernel virtual address of the PTE. Should be L3 PTE. May also work with L2 TTEs for certain devices.
1102 ptd
= GetPtDesc(KVToPhysARM(pte
))
1103 print "descriptor: {:#x}".format(ptd
)
1104 print "pmap: {:#x}".format(ptd
.pmap
)
1105 pt_index
= (pte
% kern
.globals.page_size
) / page_size
1106 pte_pgoff
= pte
% page_size
1107 if kern
.arch
.startswith('arm64'):
1108 pte_pgoff
= pte_pgoff
/ 8
1109 nttes
= page_size
/ 8
1111 pte_pgoff
= pte_pgoff
/ 4
1112 nttes
= page_size
/ 4
1113 if ptd
.ptd_info
[pt_index
].refcnt
== 0x4000:
1115 granule
= nttes
* page_size
1119 print "maps {}: {:#x}".format("IPA" if stage2
else "VA", long(unsigned(ptd
.ptd_info
[pt_index
].va
)) + (pte_pgoff
* granule
))
1120 pteval
= long(unsigned(dereference(kern
.GetValueFromAddress(unsigned(pte
), 'pt_entry_t *'))))
1121 print "value: {:#x}".format(pteval
)
1122 if kern
.arch
.startswith('arm64'):
1123 print "level: {:d}".format(level
)
1124 PmapDecodeTTEARM64(pteval
, level
, stage2
)
1125 elif kern
.arch
== 'arm':
1126 PmapDecodeTTEARM(pteval
, 2, vSCRIPT
)
1128 @lldb_command('showpte')
1129 def ShowPTE(cmd_args
=None):
1130 """ Display vital information about the page table entry at VA <pte>
1131 Syntax: (lldb) showpte <pte_va> [4k|16k|16k_s2]
1133 if cmd_args
== None or len(cmd_args
) < 1:
1134 raise ArgumentError("Too few arguments to showpte.")
1136 if kern
.arch
== 'arm':
1137 ShowPTEARM(kern
.GetValueFromAddress(cmd_args
[0], 'unsigned long'), kern
.globals.page_size
)
1138 elif kern
.arch
.startswith('arm64'):
1139 pmap_pt_attr
= kern
.globals.native_pt_attr
if len(cmd_args
) < 2 else GetMemoryAttributesFromUser(cmd_args
[1])
1140 if pmap_pt_attr
is None:
1141 raise ArgumentError("Invalid translation attribute type.")
1143 stage2
= bool(pmap_pt_attr
.stage2
if hasattr(pmap_pt_attr
, 'stage2') else False)
1144 ShowPTEARM(kern
.GetValueFromAddress(cmd_args
[0], 'unsigned long'), pmap_pt_attr
.pta_page_size
, stage2
)
1146 raise NotImplementedError("showpte does not support {0}".format(kern
.arch
))
1148 def FindMappingAtLevelARM(pmap
, tt
, nttes
, level
, va
, action
):
1149 """ Perform the specified action for all valid mappings in an ARM translation table
1150 pmap: owner of the translation table
1151 tt: translation table or page table
1152 nttes: number of entries in tt
1153 level: translation table level, 1 or 2
1154 action: callback for each valid TTE
1156 for i
in range(nttes
):
1161 if tte
& 0x3 == 0x1:
1164 va_size
= kern
.globals.page_size
* 256
1165 paddr
= tte
& 0xFFFFFC00
1166 elif tte
& 0x3 == 0x2:
1168 if (tte
& 0x40000) == 0x40000:
1170 paddr
= tte
& 0xFF000000
1173 paddr
= tte
& 0xFFF00000
1176 elif (tte
& 0x3) == 0x1:
1179 paddr
= tte
& 0xFFFF0000
1180 elif (tte
& 0x3) != 0:
1183 paddr
= tte
& 0xFFFFF000
1188 mapped_va
= va
+ (va_size
* i
)
1189 if action(pmap
, level
, type, addressof(tt
[i
]), paddr
, mapped_va
, granule
):
1190 if level
== 1 and (tte
& 0x3) == 0x1:
1191 tt_next
= kern
.GetValueFromAddress(kern
.PhysToKernelVirt(paddr
), 'tt_entry_t *')
1192 FindMappingAtLevelARM(pmap
, tt_next
, granule
/ 4, level
+ 1, mapped_va
, action
)
1193 except Exception as exc
:
1194 print "Unable to access tte {:#x}".format(unsigned(addressof(tt
[i
])))
1196 def FindMappingAtLevelARM64(pmap
, tt
, nttes
, level
, va
, action
):
1197 """ Perform the specified action for all valid mappings in an ARM64 translation table
1198 pmap: owner of the translation table
1199 tt: translation table or page table
1200 nttes: number of entries in tt
1201 level: translation table level, 1 2 or 3
1202 action: callback for each valid TTE
1204 # Obtain pmap attributes
1205 pmap_pt_attr
= pmap
.pmap_pt_attr
if hasattr(pmap
, 'pmap_pt_attr') else kern
.globals.native_pt_attr
1206 page_size
= pmap_pt_attr
.pta_page_size
1207 page_offset_mask
= (page_size
- 1)
1208 page_base_mask
= ((1 << ARM64_VMADDR_BITS
) - 1) & (~page_offset_mask
)
1209 max_level
= unsigned(pmap_pt_attr
.pta_max_level
)
1211 for i
in range(nttes
):
1214 if tte
& 0x1 == 0x0:
1218 paddr
= unsigned(tte
) & unsigned(page_base_mask
)
1221 if tte
& 0x2 == 0x0 or level
== max_level
:
1222 type = 'block' if level
< max_level
else 'entry'
1223 granule
= PmapBlockOffsetMaskARM64(page_size
, level
) + 1
1225 # Handle page table entry
1228 tt_next
= kern
.GetValueFromAddress(kern
.PhysToKernelVirt(paddr
), 'tt_entry_t *')
1230 mapped_va
= long(unsigned(va
)) + ((PmapBlockOffsetMaskARM64(page_size
, level
) + 1) * i
)
1231 if action(pmap
, level
, type, addressof(tt
[i
]), paddr
, mapped_va
, granule
):
1232 if tt_next
is not None:
1233 FindMappingAtLevelARM64(pmap
, tt_next
, granule
/ ARM64_TTE_SIZE
, level
+ 1, mapped_va
, action
)
1235 except Exception as exc
:
1236 print "Unable to access tte {:#x}".format(unsigned(addressof(tt
[i
])))
1238 def ScanPageTables(action
, targetPmap
=None):
1239 """ Perform the specified action for all valid mappings in all page tables,
1240 optionally restricted to a single pmap.
1241 pmap: pmap whose page table should be scanned. If None, all pmaps on system will be scanned.
1243 print "Scanning all available translation tables. This may take a long time..."
1244 def ScanPmap(pmap
, action
):
1245 if kern
.arch
.startswith('arm64'):
1246 # Obtain pmap attributes
1247 pmap_pt_attr
= pmap
.pmap_pt_attr
if hasattr(pmap
, 'pmap_pt_attr') else kern
.globals.native_pt_attr
1248 granule
= pmap_pt_attr
.pta_page_size
1249 level
= unsigned(pmap_pt_attr
.pta_root_level
)
1250 root_pgtable_num_ttes
= (unsigned(pmap_pt_attr
.pta_level_info
[level
].index_mask
) >> \
1251 unsigned(pmap_pt_attr
.pta_level_info
[level
].shift
)) + 1
1252 elif kern
.arch
== 'arm':
1253 granule
= pmap
.tte_index_max
* 4
1255 if action(pmap
, pmap_pt_attr
.pta_root_level
, 'root', pmap
.tte
, unsigned(pmap
.ttep
), pmap
.min, granule
):
1256 if kern
.arch
.startswith('arm64'):
1257 FindMappingAtLevelARM64(pmap
, pmap
.tte
, root_pgtable_num_ttes
, level
, pmap
.min, action
)
1258 elif kern
.arch
== 'arm':
1259 FindMappingAtLevelARM(pmap
, pmap
.tte
, pmap
.tte_index_max
, 1, pmap
.min, action
)
1261 if targetPmap
is not None:
1262 ScanPmap(kern
.GetValueFromAddress(targetPmap
, 'pmap_t'), action
)
1264 for pmap
in IterateQueue(kern
.globals.map_pmap_list
, 'pmap_t', 'pmaps'):
1265 ScanPmap(pmap
, action
)
1267 @lldb_command('showallmappings')
1268 def ShowAllMappings(cmd_args
=None):
1269 """ Find and display all available mappings on the system for
1270 <physical_address>. Optionally only searches the pmap
1271 specified by [<pmap>]
1272 Syntax: (lldb) showallmappings <physical_address> [<pmap>]
1273 WARNING: this macro can take a long time (up to 30min.) to complete!
1275 if cmd_args
== None or len(cmd_args
) < 1:
1276 raise ArgumentError("Too few arguments to showallmappings.")
1277 if not kern
.arch
.startswith('arm'):
1278 raise NotImplementedError("showallmappings does not support {0}".format(kern
.arch
))
1279 pa
= kern
.GetValueFromAddress(cmd_args
[0], 'unsigned long')
1281 if len(cmd_args
) > 1:
1282 targetPmap
= cmd_args
[1]
1283 def printMatchedMapping(pmap
, level
, type, tte
, paddr
, va
, granule
):
1284 if paddr
<= pa
< (paddr
+ granule
):
1285 print "pmap: {:#x}: L{:d} {:s} at {:#x}: [{:#x}, {:#x}), maps va {:#x}".format(pmap
, level
, type, unsigned(tte
), paddr
, paddr
+ granule
, va
)
1287 ScanPageTables(printMatchedMapping
, targetPmap
)
1289 @lldb_command('showptusage')
1290 def ShowPTUsage(cmd_args
=None):
1291 """ Display a summary of pagetable allocations for a given pmap.
1292 Syntax: (lldb) showptusage [<pmap>]
1293 WARNING: this macro can take a long time (> 1hr) to complete!
1295 if not kern
.arch
.startswith('arm'):
1296 raise NotImplementedError("showptusage does not support {0}".format(kern
.arch
))
1298 if len(cmd_args
) > 0:
1299 targetPmap
= cmd_args
[0]
1304 def printValidTTE(pmap
, level
, type, tte
, paddr
, va
, granule
):
1306 nested_region_addr
= long(unsigned(pmap
.nested_region_addr
))
1307 nested_region_end
= nested_region_addr
+ long(unsigned(pmap
.nested_region_size
))
1308 if lastPmap
[0] is None or (pmap
!= lastPmap
[0]):
1310 numPmaps
[0] = numPmaps
[0] + 1
1311 print ("pmap {:#x}:".format(pmap
))
1314 if (level
== 2) and (va
>= nested_region_addr
) and (va
< nested_region_end
):
1315 ptd
= GetPtDesc(paddr
)
1316 if ptd
.pmap
!= pmap
:
1319 numUnnested
[0] = numUnnested
[0] + 1
1320 unnested
= " (likely unnested)"
1321 numTables
[0] = numTables
[0] + 1
1322 print (" " * 4 * int(level
)) + "L{:d} entry at {:#x}, maps {:#x}".format(level
, unsigned(tte
), va
) + unnested
1327 ScanPageTables(printValidTTE
, targetPmap
)
1328 print("{:d} table(s), {:d} of them likely unnested, in {:d} pmap(s)".format(numTables
[0], numUnnested
[0], numPmaps
[0]))
1330 def checkPVList(pmap
, level
, type, tte
, paddr
, va
, granule
):
1331 """ Checks an ARM physical-to-virtual mapping list for consistency errors.
1332 pmap: owner of the translation table
1333 level: translation table level. PV lists will only be checked for L2 (arm32) or L3 (arm64) tables.
1335 tte: KVA of PTE to check for presence in PV list. If None, presence check will be skipped.
1336 paddr: physical address whose PV list should be checked. Need not be page-aligned.
1339 vm_first_phys
= unsigned(kern
.globals.vm_first_phys
)
1340 vm_last_phys
= unsigned(kern
.globals.vm_last_phys
)
1341 page_size
= kern
.globals.page_size
1342 if kern
.arch
.startswith('arm64'):
1343 page_offset_mask
= (page_size
- 1)
1344 page_base_mask
= ((1 << ARM64_VMADDR_BITS
) - 1) & (~page_offset_mask
)
1345 paddr
= paddr
& page_base_mask
1347 pvh_set_bits
= PVH_HIGH_FLAGS_ARM64
1348 elif kern
.arch
== 'arm':
1349 page_base_mask
= 0xFFFFF000
1350 paddr
= paddr
& page_base_mask
1352 pvh_set_bits
= PVH_HIGH_FLAGS_ARM32
1353 if level
< max_level
or paddr
< vm_first_phys
or paddr
>= vm_last_phys
:
1355 pn
= (paddr
- vm_first_phys
) / page_size
1356 pvh
= unsigned(kern
.globals.pv_head_table
[pn
]) | pvh_set_bits
1357 pvh_type
= pvh
& 0x3
1358 if pmap
is not None:
1359 pmap_str
= "pmap: {:#x}: ".format(pmap
)
1363 tte_str
= "pte {:#x} ({:#x}): ".format(unsigned(tte
), paddr
)
1365 tte_str
= "paddr {:#x}: ".format(paddr
)
1366 if pvh_type
== 0 or pvh_type
== 3:
1367 print "{:s}{:s}unexpected PVH type {:d}".format(pmap_str
, tte_str
, pvh_type
)
1370 if tte
is not None and ptep
!= unsigned(tte
):
1371 print "{:s}{:s}PVH mismatch ({:#x})".format(pmap_str
, tte_str
, ptep
)
1373 pte
= long(unsigned(dereference(kern
.GetValueFromAddress(ptep
, 'pt_entry_t *')))) & page_base_mask
1375 print "{:s}{:s}PVH {:#x} maps wrong page ({:#x}) ".format(pmap_str
, tte_str
, ptep
, pte
)
1376 except Exception as exc
:
1377 print "{:s}{:s}Unable to read PVH {:#x}".format(pmap_str
, tte_str
, ptep
)
1382 pve
= kern
.GetValueFromAddress(pvep
, "pv_entry_t *")
1383 pvep
= unsigned(pve
.pve_next
) & ~
0x1
1384 ptep
= unsigned(pve
.pve_ptep
) & ~
0x3
1385 if tte
is not None and ptep
== unsigned(tte
):
1388 pte
= long(unsigned(dereference(kern
.GetValueFromAddress(ptep
, 'pt_entry_t *')))) & page_base_mask
1390 print "{:s}{:s}PVE {:#x} maps wrong page ({:#x}) ".format(pmap_str
, tte_str
, ptep
, pte
)
1391 except Exception as exc
:
1392 print "{:s}{:s}Unable to read PVE {:#x}".format(pmap_str
, tte_str
, ptep
)
1393 if tte
is not None and not tte_match
:
1394 print "{:s}{:s}not found in PV list".format(pmap_str
, tte_str
, paddr
)
1397 @lldb_command('pv_check', 'P')
1398 def PVCheck(cmd_args
=None, cmd_options
={}):
1399 """ Check the physical-to-virtual mapping for a given PTE or physical address
1400 Syntax: (lldb) pv_check <addr> [-p]
1401 -P : Interpret <addr> as a physical address rather than a PTE
1403 if cmd_args
== None or len(cmd_args
) < 1:
1404 raise ArgumentError("Too few arguments to pv_check.")
1405 if kern
.arch
== 'arm':
1407 elif kern
.arch
.startswith('arm64'):
1410 raise NotImplementedError("pv_check does not support {0}".format(kern
.arch
))
1411 if "-P" in cmd_options
:
1413 pa
= long(unsigned(kern
.GetValueFromAddress(cmd_args
[0], "unsigned long")))
1415 pte
= kern
.GetValueFromAddress(cmd_args
[0], 'pt_entry_t *')
1416 pa
= long(unsigned(dereference(pte
)))
1417 checkPVList(None, level
, None, pte
, pa
, 0, None)
1419 @lldb_command('check_pmaps')
1420 def CheckPmapIntegrity(cmd_args
=None):
1421 """ Performs a system-wide integrity check of all PTEs and associated PV lists.
1422 Optionally only checks the pmap specified by [<pmap>]
1423 Syntax: (lldb) check_pmaps [<pmap>]
1424 WARNING: this macro can take a HUGE amount of time (several hours) if you do not
1425 specify [pmap] to limit it to a single pmap. It will also give false positives
1426 for kernel_pmap, as we do not create PV entries for static kernel mappings on ARM.
1427 Use of this macro without the [<pmap>] argument is heavily discouraged.
1429 if not kern
.arch
.startswith('arm'):
1430 raise NotImplementedError("check_pmaps does not support {0}".format(kern
.arch
))
1432 if len(cmd_args
) > 0:
1433 targetPmap
= cmd_args
[0]
1434 ScanPageTables(checkPVList
, targetPmap
)
1436 @lldb_command('pmapsforledger')
1437 def PmapsForLedger(cmd_args
=None):
1438 """ Find and display all pmaps currently using <ledger>.
1439 Syntax: (lldb) pmapsforledger <ledger>
1441 if cmd_args
== None or len(cmd_args
) < 1:
1442 raise ArgumentError("Too few arguments to pmapsforledger.")
1443 if not kern
.arch
.startswith('arm'):
1444 raise NotImplementedError("pmapsforledger does not support {0}".format(kern
.arch
))
1445 ledger
= kern
.GetValueFromAddress(cmd_args
[0], 'ledger_t')
1446 for pmap
in IterateQueue(kern
.globals.map_pmap_list
, 'pmap_t', 'pmaps'):
1447 if pmap
.ledger
== ledger
:
1448 print "pmap: {:#x}".format(pmap
)