6 def ReadPhysInt(phys_addr
, bitsize
= 64, cpuval
= None):
7 """ Read a physical memory data based on address.
9 phys_addr : int - Physical address to read
10 bitsize : int - defines how many bytes to read. defaults to 64 bit
11 cpuval : None (optional)
13 int - int value read from memory. in case of failure 0xBAD10AD is returned.
15 if "kdp" == GetConnectionProtocol():
16 return KDPReadPhysMEM(phys_addr
, bitsize
)
18 #NO KDP. Attempt to use physical memory
19 paddr_in_kva
= kern
.PhysToKernelVirt(long(phys_addr
))
22 return kern
.GetValueFromAddress(paddr_in_kva
, 'uint64_t *').GetSBValue().Dereference().GetValueAsUnsigned()
24 return kern
.GetValueFromAddress(paddr_in_kva
, 'uint32_t *').GetSBValue().Dereference().GetValueAsUnsigned()
26 return kern
.GetValueFromAddress(paddr_in_kva
, 'uint16_t *').GetSBValue().Dereference().GetValueAsUnsigned()
28 return kern
.GetValueFromAddress(paddr_in_kva
, 'uint8_t *').GetSBValue().Dereference().GetValueAsUnsigned()
31 @lldb_command('readphys')
32 def ReadPhys(cmd_args
= None):
33 """ Reads the specified untranslated address
34 The argument is interpreted as a physical address, and the 64-bit word
35 addressed is displayed.
36 usage: readphys <nbits> <address>
38 address: 1234 or 0x1234
40 if cmd_args
== None or len(cmd_args
) < 2:
41 print "Insufficient arguments.", ReadPhys
.__doc
__
44 nbits
= ArgumentStringToInt(cmd_args
[0])
45 phys_addr
= ArgumentStringToInt(cmd_args
[1])
46 print "{0: <#x}".format(ReadPhysInt(phys_addr
, nbits
))
49 lldb_alias('readphys8', 'readphys 8 ')
50 lldb_alias('readphys16', 'readphys 16 ')
51 lldb_alias('readphys32', 'readphys 32 ')
52 lldb_alias('readphys64', 'readphys 64 ')
54 def KDPReadPhysMEM(address
, bits
):
55 """ Setup the state for READPHYSMEM64 commands for reading data via kdp
57 address : int - address where to read the data from
58 bits : int - number of bits in the intval (8/16/32/64)
60 int: read value from memory.
61 0xBAD10AD: if failed to read data.
64 if "kdp" != GetConnectionProtocol():
65 print "Target is not connected over kdp. Nothing to do here."
68 input_address
= unsigned(addressof(kern
.globals.manual_pkt
.input))
69 len_address
= unsigned(addressof(kern
.globals.manual_pkt
.len))
70 data_address
= unsigned(addressof(kern
.globals.manual_pkt
.data
))
71 if not WriteInt32ToMemoryAddress(0, input_address
):
74 kdp_pkt_size
= GetType('kdp_readphysmem64_req_t').GetByteSize()
75 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
78 data_addr
= int(addressof(kern
.globals.manual_pkt
))
79 pkt
= kern
.GetValueFromAddress(data_addr
, 'kdp_readphysmem64_req_t *')
81 header_value
=GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_READPHYSMEM64'), length
=kdp_pkt_size
)
83 if ( WriteInt64ToMemoryAddress((header_value
), int(addressof(pkt
.hdr
))) and
84 WriteInt64ToMemoryAddress(address
, int(addressof(pkt
.address
))) and
85 WriteInt32ToMemoryAddress((bits
/8), int(addressof(pkt
.nbytes
))) and
86 WriteInt16ToMemoryAddress(xnudefines
.lcpu_self
, int(addressof(pkt
.lcpu
)))
89 if WriteInt32ToMemoryAddress(1, input_address
):
90 # now read data from the kdp packet
91 data_address
= unsigned(addressof(kern
.GetValueFromAddress(int(addressof(kern
.globals.manual_pkt
.data
)), 'kdp_readphysmem64_reply_t *').data
))
93 retval
= kern
.GetValueFromAddress(data_address
, 'uint64_t *').GetSBValue().Dereference().GetValueAsUnsigned()
95 retval
= kern
.GetValueFromAddress(data_address
, 'uint32_t *').GetSBValue().Dereference().GetValueAsUnsigned()
97 retval
= kern
.GetValueFromAddress(data_address
, 'uint16_t *').GetSBValue().Dereference().GetValueAsUnsigned()
99 retval
= kern
.GetValueFromAddress(data_address
, 'uint8_t *').GetSBValue().Dereference().GetValueAsUnsigned()
103 def KDPWritePhysMEM(address
, intval
, bits
):
104 """ Setup the state for WRITEPHYSMEM64 commands for saving data in kdp
106 address : int - address where to save the data
107 intval : int - integer value to be stored in memory
108 bits : int - number of bits in the intval (8/16/32/64)
110 boolean: True if the write succeeded.
112 if "kdp" != GetConnectionProtocol():
113 print "Target is not connected over kdp. Nothing to do here."
115 input_address
= unsigned(addressof(kern
.globals.manual_pkt
.input))
116 len_address
= unsigned(addressof(kern
.globals.manual_pkt
.len))
117 data_address
= unsigned(addressof(kern
.globals.manual_pkt
.data
))
118 if not WriteInt32ToMemoryAddress(0, input_address
):
121 kdp_pkt_size
= GetType('kdp_writephysmem64_req_t').GetByteSize()
122 if not WriteInt32ToMemoryAddress(kdp_pkt_size
, len_address
):
125 data_addr
= int(addressof(kern
.globals.manual_pkt
))
126 pkt
= kern
.GetValueFromAddress(data_addr
, 'kdp_writephysmem64_req_t *')
128 header_value
=GetKDPPacketHeaderInt(request
=GetEnumValue('kdp_req_t::KDP_WRITEPHYSMEM64'), length
=kdp_pkt_size
)
130 if ( WriteInt64ToMemoryAddress((header_value
), int(addressof(pkt
.hdr
))) and
131 WriteInt64ToMemoryAddress(address
, int(addressof(pkt
.address
))) and
132 WriteInt32ToMemoryAddress((bits
/8), int(addressof(pkt
.nbytes
))) and
133 WriteInt16ToMemoryAddress(xnudefines
.lcpu_self
, int(addressof(pkt
.lcpu
)))
137 if not WriteInt8ToMemoryAddress(intval
, int(addressof(pkt
.data
))):
140 if not WriteInt16ToMemoryAddress(intval
, int(addressof(pkt
.data
))):
143 if not WriteInt32ToMemoryAddress(intval
, int(addressof(pkt
.data
))):
146 if not WriteInt64ToMemoryAddress(intval
, int(addressof(pkt
.data
))):
148 if WriteInt32ToMemoryAddress(1, input_address
):
153 def WritePhysInt(phys_addr
, int_val
, bitsize
= 64):
154 """ Write and integer value in a physical memory data based on address.
156 phys_addr : int - Physical address to read
157 int_val : int - int value to write in memory
158 bitsize : int - defines how many bytes to read. defaults to 64 bit
160 bool - True if write was successful.
162 if "kdp" == GetConnectionProtocol():
163 if not KDPWritePhysMEM(phys_addr
, int_val
, bitsize
):
164 print "Failed to write via KDP."
167 #We are not connected via KDP. So do manual math and savings.
168 print "Failed: Write to physical memory is not supported for %s connection." % GetConnectionProtocol()
171 @lldb_command('writephys')
172 def WritePhys(cmd_args
=None):
173 """ writes to the specified untranslated address
174 The argument is interpreted as a physical address, and the 64-bit word
175 addressed is displayed.
176 usage: writephys <nbits> <address> <value>
178 address: 1234 or 0x1234
179 value: int value to be written
180 ex. (lldb)writephys 16 0x12345abcd 0x25
182 if cmd_args
== None or len(cmd_args
) < 3:
183 print "Invalid arguments.", WritePhys
.__doc
__
185 nbits
= ArgumentStringToInt(cmd_args
[0])
186 phys_addr
= ArgumentStringToInt(cmd_args
[1])
187 int_value
= ArgumentStringToInt(cmd_args
[2])
188 print WritePhysInt(phys_addr
, int_value
, nbits
)
191 lldb_alias('writephys8', 'writephys 8 ')
192 lldb_alias('writephys16', 'writephys 16 ')
193 lldb_alias('writephys32', 'writephys 32 ')
194 lldb_alias('writephys64', 'writephys 64 ')
196 def _PT_Step(paddr
, index
, verbose_level
= vSCRIPT
):
198 Step to lower-level page table and print attributes
199 paddr: current page table entry physical address
200 index: current page table entry index (0..511)
201 verbose_level: vHUMAN: print nothing
202 vSCRIPT: print basic information
203 vDETAIL: print basic information and hex table dump
204 returns: (pt_paddr, pt_valid, pt_large)
205 pt_paddr: next level page table entry physical address
207 pt_valid: 1 if $kgm_pt_paddr is valid, 0 if the walk
209 pt_large: 1 if kgm_pt_paddr is a page frame address
210 of a large page and not another page table entry
212 entry_addr
= paddr
+ (8 * index
)
213 entry
= ReadPhysInt(entry_addr
, 64, xnudefines
.lcpu_self
)
215 if verbose_level
>= vDETAIL
:
216 for pte_loop
in range(0, 512):
217 paddr_tmp
= paddr
+ (8 * pte_loop
)
218 out_string
+= "{0: <#020x}:\t {1: <#020x}\n".format(paddr_tmp
, ReadPhysInt(paddr_tmp
, 64, xnudefines
.lcpu_self
))
219 paddr_mask
= ~
((0xfff<<52) |
0xfff)
220 paddr_large_mask
= ~
((0xfff<<52) |
0x1fffff)
224 if verbose_level
< vSCRIPT
:
228 pt_paddr
= entry
& paddr_mask
229 if entry
& (0x1 <<7):
231 pt_paddr
= entry
& paddr_large_mask
233 out_string
+= "{0: <#020x}:\n\t{1:#020x}\n\t".format(entry_addr
, entry
)
235 out_string
+= " valid"
236 pt_paddr
= entry
& paddr_mask
239 out_string
+= " invalid"
242 #Stop decoding other bits
244 if entry
& (0x1 << 1):
245 out_string
+= " writable"
247 out_string
+= " read-only"
249 if entry
& (0x1 << 2):
250 out_string
+= " user"
252 out_string
+= " supervisor"
254 if entry
& (0x1 << 3):
257 if entry
& (0x1 << 4):
260 if entry
& (0x1 << 5):
261 out_string
+= " accessed"
263 if entry
& (0x1 << 6):
264 out_string
+= " dirty"
266 if entry
& (0x1 << 7):
267 out_string
+= " large"
272 if entry
& (0x1 << 8):
273 out_string
+= " global"
275 if entry
& (0x3 << 9):
276 out_string
+= " avail:{0:x}".format((entry
>> 9) & 0x3)
278 if entry
& (0x1 << 63):
279 out_string
+= " noexec"
281 return (pt_paddr
, pt_valid
, pt_large
)
286 def _PmapL4Walk(pmap_addr_val
,vaddr
, verbose_level
= vSCRIPT
):
287 """ Walk the l4 pmap entry.
288 params: pmap_addr_val - core.value representing kernel data of type pmap_addr_t
289 vaddr : int - virtual address to walk
291 is_cpu64_bit
= int(kern
.globals.cpu_64bit
)
292 pt_paddr
= unsigned(pmap_addr_val
)
293 pt_valid
= (unsigned(pmap_addr_val
) != 0)
296 if pt_valid
and is_cpu64_bit
:
297 # Lookup bits 47:39 of linear address in PML4T
298 pt_index
= (vaddr
>> 39) & 0x1ff
299 pframe_offset
= vaddr
& 0x7fffffffff
300 if verbose_level
> vHUMAN
:
301 print "pml4 (index {0:d}):".format(pt_index
)
302 (pt_paddr
, pt_valid
, pt_large
) = _PT_Step(pt_paddr
, pt_index
, verbose_level
)
304 # Lookup bits 38:30 of the linear address in PDPT
305 pt_index
= (vaddr
>> 30) & 0x1ff
306 pframe_offset
= vaddr
& 0x3fffffff
307 if verbose_level
> vHUMAN
:
308 print "pdpt (index {0:d}):".format(pt_index
)
309 (pt_paddr
, pt_valid
, pt_large
) = _PT_Step(pt_paddr
, pt_index
, verbose_level
)
310 if pt_valid
and not pt_large
:
311 #Lookup bits 29:21 of the linear address in PDPT
312 pt_index
= (vaddr
>> 21) & 0x1ff
313 pframe_offset
= vaddr
& 0x1fffff
314 if verbose_level
> vHUMAN
:
315 print "pdt (index {0:d}):".format(pt_index
)
316 (pt_paddr
, pt_valid
, pt_large
) = _PT_Step(pt_paddr
, pt_index
, verbose_level
)
317 if pt_valid
and not pt_large
:
318 #Lookup bits 20:21 of linear address in PT
319 pt_index
= (vaddr
>> 12) & 0x1ff
320 pframe_offset
= vaddr
& 0xfff
321 if verbose_level
> vHUMAN
:
322 print "pt (index {0:d}):".format(pt_index
)
323 (pt_paddr
, pt_valid
, pt_large
) = _PT_Step(pt_paddr
, pt_index
, verbose_level
)
325 paddr_isvalid
= False
327 paddr
= pt_paddr
+ pframe_offset
330 if verbose_level
> vHUMAN
:
332 pvalue
= ReadPhysInt(paddr
, 32, xnudefines
.lcpu_self
)
333 print "phys {0: <#020x}: {1: <#020x}".format(paddr
, pvalue
)
335 print "no translation"
339 def _PmapWalkARMLevel1Section(tte
, vaddr
, verbose_level
= vSCRIPT
):
342 #Supersection or just section?
343 if (tte
& 0x40000) == 0x40000:
344 paddr
= ( (tte
& 0xFF000000) |
(vaddr
& 0x00FFFFFF) )
346 paddr
= ( (tte
& 0xFFF00000) |
(vaddr
& 0x000FFFFF) )
348 if verbose_level
>= vSCRIPT
:
349 out_string
+= "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte
), tte
)
350 #bit [1:0] evaluated in PmapWalkARM
352 b_bit
= (tte
& 0x4) >> 2
354 c_bit
= (tte
& 0x8) >> 3
357 out_string
+= "no-execute"
359 out_string
+= "execute"
360 #Domain bit [8:5] if not supersection
361 if (tte
& 0x40000) == 0x0:
362 out_string
+= " domain ({:d})".format(((tte
& 0x1e0) >> 5) )
364 out_string
+= " imp({:d})".format( ((tte
& 0x200) >> 9) )
365 # AP bit 15 and [11:10] merged to a single 3 bit value
366 access
= ( (tte
& 0xc00) >> 10 ) |
((tte
& 0x8000) >> 13)
367 out_string
+= xnudefines
.arm_level2_access_strings
[access
]
370 tex_bits
= ((tte
& 0x7000) >> 12)
371 #Print TEX, C , B all together
372 out_string
+= " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format(
373 1 if (tex_bits
& 0x4) else 0,
374 1 if (tex_bits
& 0x2) else 0,
375 1 if (tex_bits
& 0x1) else 0,
381 out_string
+= " shareable"
383 out_string
+= " not-shareable"
386 out_string
+= " not-global"
388 out_string
+= " global"
389 # Supersection bit 18
391 out_string
+= " supersection"
393 out_string
+= " section"
396 out_string
+= " no-secure"
398 out_string
+= " secure"
405 def _PmapWalkARMLevel2(tte
, vaddr
, verbose_level
= vSCRIPT
):
406 """ Pmap walk the level 2 tte.
410 returns: str - description of the tte + additional informaiton based on verbose_level
412 pte_base
= kern
.PhysToKernelVirt(tte
& 0xFFFFFC00)
413 pte_index
= (vaddr
>> 12) & 0xFF
414 pte_base_val
= kern
.GetValueFromAddress(pte_base
, 'pt_entry_t *')
415 pte
= pte_base_val
[pte_index
]
417 if verbose_level
>= vSCRIPT
:
418 out_string
+= "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte
), tte
)
419 # bit [1:0] evaluated in PmapWalkARM
422 out_string
+= ' no-secure'
424 out_string
+= ' secure'
426 out_string
+= " domain({:d})".format(((tte
& 0x1e0) >> 5))
428 out_string
+= " imp({:d})".format( ((tte
& 0x200) >> 9))
430 if verbose_level
>= vSCRIPT
:
431 out_string
+= "second-level table (index {:d}):\n".format(pte_index
)
432 if verbose_level
>= vDETAIL
:
434 tmp
= pte_base_val
[i
]
435 out_string
+= "{0: <#020x}:\t{1: <#020x}\n".format(addressof(tmp
), unsigned(tmp
))
439 paddr
= (unsigned(pte
) & 0xFFFFF000) |
(vaddr
& 0xFFF)
441 if verbose_level
>= vSCRIPT
:
442 out_string
+= " {0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(pte
), unsigned(pte
))
443 if (pte
& 0x3) == 0x0:
444 out_string
+= " invalid"
446 if (pte
& 0x3) == 0x1:
447 out_string
+= " large"
449 if pte
& 0x8000 == 0x8000:
450 out_string
+= " no-execute"
452 out_string
+= " execute"
454 out_string
+= " small"
456 if (pte
& 0x1) == 0x01:
457 out_string
+= " no-execute"
459 out_string
+= " execute"
461 b_bit
= (pte
& 0x4) >> 2
462 c_bit
= (pte
& 0x8) >> 3
463 # AP bit 9 and [5:4], merged to a single 3-bit value
464 access
= (pte
& 0x30) >> 4 |
(pte
& 0x200) >> 7
465 out_string
+= xnudefines
.arm_level2_access_strings
[access
]
467 #TEX bit [14:12] for large, [8:6] for small
468 tex_bits
= ((pte
& 0x1c0) >> 6)
469 if (pte
& 0x3) == 0x1:
470 tex_bits
= ((pte
& 0x7000) >> 12)
472 # Print TEX, C , B alltogether
473 out_string
+= " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format(
474 1 if (tex_bits
& 0x4) else 0,
475 1 if (tex_bits
& 0x2) else 0,
476 1 if (tex_bits
& 0x1) else 0,
482 out_string
+= " shareable"
484 out_string
+= " not-shareable"
488 out_string
+= " not-global"
490 out_string
+= " global"
493 #end of level 2 walking of arm
496 def PmapWalkARM(pmap
, vaddr
, verbose_level
= vHUMAN
):
497 """ Pmap walking for ARM kernel.
499 pmapval: core.value - representing pmap_t in kernel
500 vaddr: int - integer representing virtual address to walk
503 # shift by TTESHIFT (20) to get tte index
504 tte_index
= ((vaddr
- unsigned(pmap
.min)) >> 20 )
505 tte
= pmap
.tte
[tte_index
]
506 if verbose_level
>= vSCRIPT
:
507 print "First-level table (index {:d}):".format(tte_index
)
508 if verbose_level
>= vDETAIL
:
509 for i
in range(0, 4096):
510 ptr
= unsigned(addressof(pmap
.tte
[i
]))
511 val
= unsigned(pmap
.tte
[i
])
512 print "{0: <#020x}:\t {1: <#020x}".format(ptr
, val
)
513 if (tte
& 0x3) == 0x1:
514 paddr
= _PmapWalkARMLevel2(tte
, vaddr
, verbose_level
)
515 elif (tte
& 0x3) == 0x2 :
516 paddr
= _PmapWalkARMLevel1Section(tte
, vaddr
, verbose_level
)
519 if verbose_level
>= vSCRIPT
:
520 print "Invalid First-Level Translation Table Entry: {0: #020x}".format(tte
)
522 if verbose_level
>= vHUMAN
:
524 print "Translation of {:#x} is {:#x}.".format(vaddr
, paddr
)
526 print "(no translation)"
530 def PmapWalkX86_64(pmapval
, vaddr
):
532 params: pmapval - core.value representing pmap_t in kernel
533 vaddr: int - int representing virtual address to walk
535 _PmapL4Walk(pmapval
.pm_cr3
, vaddr
, config
['verbosity'])
537 def assert_64bit(val
):
540 def PmapWalk(pmap
, vaddr
, verbose_level
= vHUMAN
):
541 if kern
.arch
== 'x86_64':
542 return PmapWalkX86_64(pmap
, vaddr
)
543 elif kern
.arch
== 'arm':
544 return PmapWalkARM(pmap
, vaddr
, verbose_level
)
546 raise NotImplementedError("PmapWalk does not support {0}".format(kern
.arch
))
548 @lldb_command('pmap_walk')
549 def PmapWalkHelper(cmd_args
=None):
550 """ Perform a page-table walk in <pmap> for <virtual_address>.
551 Syntax: (lldb) pmap_walk <pmap> <virtual_address> [-v]
552 Multiple -v's can be specified for increased verbosity
554 if cmd_args
== None or len(cmd_args
) < 2:
555 raise ArgumentError("Too few arguments to pmap_walk.")
557 pmap
= kern
.GetValueAsType(cmd_args
[0], 'pmap_t')
558 addr
= unsigned(kern
.GetValueFromAddress(cmd_args
[1], 'void *'))
559 PmapWalk(pmap
, addr
, config
['verbosity'])