]> git.saurik.com Git - apple/xnu.git/blob - tools/lldbmacros/pmap.py
2424d2d9394edd7049c7bacba117780898d713bd
[apple/xnu.git] / tools / lldbmacros / pmap.py
1 from xnu import *
2 import xnudefines
3 from kdp import *
4 from utils import *
5
6 def ReadPhysInt(phys_addr, bitsize = 64, cpuval = None):
7 """ Read a physical memory data based on address.
8 params:
9 phys_addr : int - Physical address to read
10 bitsize : int - defines how many bytes to read. defaults to 64 bit
11 cpuval : None (optional)
12 returns:
13 int - int value read from memory. in case of failure 0xBAD10AD is returned.
14 """
15 if "kdp" == GetConnectionProtocol():
16 return KDPReadPhysMEM(phys_addr, bitsize)
17
18 #NO KDP. Attempt to use physical memory
19 paddr_in_kva = kern.PhysToKernelVirt(long(phys_addr))
20 if paddr_in_kva :
21 if bitsize == 64 :
22 return kern.GetValueFromAddress(paddr_in_kva, 'uint64_t *').GetSBValue().Dereference().GetValueAsUnsigned()
23 if bitsize == 32 :
24 return kern.GetValueFromAddress(paddr_in_kva, 'uint32_t *').GetSBValue().Dereference().GetValueAsUnsigned()
25 if bitsize == 16 :
26 return kern.GetValueFromAddress(paddr_in_kva, 'uint16_t *').GetSBValue().Dereference().GetValueAsUnsigned()
27 if bitsize == 8 :
28 return kern.GetValueFromAddress(paddr_in_kva, 'uint8_t *').GetSBValue().Dereference().GetValueAsUnsigned()
29 return 0xBAD10AD
30
31 @lldb_command('readphys')
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>
37 nbits: 8,16,32,64
38 address: 1234 or 0x1234
39 """
40 if cmd_args == None or len(cmd_args) < 2:
41 print "Insufficient arguments.", ReadPhys.__doc__
42 return False
43 else:
44 nbits = ArgumentStringToInt(cmd_args[0])
45 phys_addr = ArgumentStringToInt(cmd_args[1])
46 print "{0: <#x}".format(ReadPhysInt(phys_addr, nbits))
47 return True
48
49 lldb_alias('readphys8', 'readphys 8 ')
50 lldb_alias('readphys16', 'readphys 16 ')
51 lldb_alias('readphys32', 'readphys 32 ')
52 lldb_alias('readphys64', 'readphys 64 ')
53
54 def KDPReadPhysMEM(address, bits):
55 """ Setup the state for READPHYSMEM64 commands for reading data via kdp
56 params:
57 address : int - address where to read the data from
58 bits : int - number of bits in the intval (8/16/32/64)
59 returns:
60 int: read value from memory.
61 0xBAD10AD: if failed to read data.
62 """
63 retval = 0xBAD10AD
64 if "kdp" != GetConnectionProtocol():
65 print "Target is not connected over kdp. Nothing to do here."
66 return retval
67
68 input_address = unsigned(addressof(kern.globals.manual_pkt.input))
69 len_address = unsigned(addressof(kern.globals.manual_pkt.len))
70 data_address = unsigned(addressof(kern.globals.manual_pkt.data))
71 if not WriteInt32ToMemoryAddress(0, input_address):
72 return retval
73
74 kdp_pkt_size = GetType('kdp_readphysmem64_req_t').GetByteSize()
75 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address):
76 return retval
77
78 data_addr = int(addressof(kern.globals.manual_pkt))
79 pkt = kern.GetValueFromAddress(data_addr, 'kdp_readphysmem64_req_t *')
80
81 header_value =GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_READPHYSMEM64'), length=kdp_pkt_size)
82
83 if ( WriteInt64ToMemoryAddress((header_value), int(addressof(pkt.hdr))) and
84 WriteInt64ToMemoryAddress(address, int(addressof(pkt.address))) and
85 WriteInt32ToMemoryAddress((bits/8), int(addressof(pkt.nbytes))) and
86 WriteInt16ToMemoryAddress(xnudefines.lcpu_self, int(addressof(pkt.lcpu)))
87 ):
88
89 if WriteInt32ToMemoryAddress(1, input_address):
90 # now read data from the kdp packet
91 data_address = unsigned(addressof(kern.GetValueFromAddress(int(addressof(kern.globals.manual_pkt.data)), 'kdp_readphysmem64_reply_t *').data))
92 if bits == 64 :
93 retval = kern.GetValueFromAddress(data_address, 'uint64_t *').GetSBValue().Dereference().GetValueAsUnsigned()
94 if bits == 32 :
95 retval = kern.GetValueFromAddress(data_address, 'uint32_t *').GetSBValue().Dereference().GetValueAsUnsigned()
96 if bits == 16 :
97 retval = kern.GetValueFromAddress(data_address, 'uint16_t *').GetSBValue().Dereference().GetValueAsUnsigned()
98 if bits == 8 :
99 retval = kern.GetValueFromAddress(data_address, 'uint8_t *').GetSBValue().Dereference().GetValueAsUnsigned()
100 return retval
101
102
103 def KDPWritePhysMEM(address, intval, bits):
104 """ Setup the state for WRITEPHYSMEM64 commands for saving data in kdp
105 params:
106 address : int - address where to save the data
107 intval : int - integer value to be stored in memory
108 bits : int - number of bits in the intval (8/16/32/64)
109 returns:
110 boolean: True if the write succeeded.
111 """
112 if "kdp" != GetConnectionProtocol():
113 print "Target is not connected over kdp. Nothing to do here."
114 return False
115 input_address = unsigned(addressof(kern.globals.manual_pkt.input))
116 len_address = unsigned(addressof(kern.globals.manual_pkt.len))
117 data_address = unsigned(addressof(kern.globals.manual_pkt.data))
118 if not WriteInt32ToMemoryAddress(0, input_address):
119 return False
120
121 kdp_pkt_size = GetType('kdp_writephysmem64_req_t').GetByteSize() + (bits / 8)
122 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address):
123 return False
124
125 data_addr = int(addressof(kern.globals.manual_pkt))
126 pkt = kern.GetValueFromAddress(data_addr, 'kdp_writephysmem64_req_t *')
127
128 header_value =GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_WRITEPHYSMEM64'), length=kdp_pkt_size)
129
130 if ( WriteInt64ToMemoryAddress((header_value), int(addressof(pkt.hdr))) and
131 WriteInt64ToMemoryAddress(address, int(addressof(pkt.address))) and
132 WriteInt32ToMemoryAddress((bits/8), int(addressof(pkt.nbytes))) and
133 WriteInt16ToMemoryAddress(xnudefines.lcpu_self, int(addressof(pkt.lcpu)))
134 ):
135
136 if bits == 8:
137 if not WriteInt8ToMemoryAddress(intval, int(addressof(pkt.data))):
138 return False
139 if bits == 16:
140 if not WriteInt16ToMemoryAddress(intval, int(addressof(pkt.data))):
141 return False
142 if bits == 32:
143 if not WriteInt32ToMemoryAddress(intval, int(addressof(pkt.data))):
144 return False
145 if bits == 64:
146 if not WriteInt64ToMemoryAddress(intval, int(addressof(pkt.data))):
147 return False
148 if WriteInt32ToMemoryAddress(1, input_address):
149 return True
150 return False
151
152
153 def WritePhysInt(phys_addr, int_val, bitsize = 64):
154 """ Write and integer value in a physical memory data based on address.
155 params:
156 phys_addr : int - Physical address to read
157 int_val : int - int value to write in memory
158 bitsize : int - defines how many bytes to read. defaults to 64 bit
159 returns:
160 bool - True if write was successful.
161 """
162 if "kdp" == GetConnectionProtocol():
163 if not KDPWritePhysMEM(phys_addr, int_val, bitsize):
164 print "Failed to write via KDP."
165 return False
166 return True
167 #We are not connected via KDP. So do manual math and savings.
168 print "Failed: Write to physical memory is not supported for %s connection." % GetConnectionProtocol()
169 return False
170
171 @lldb_command('writephys')
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>
177 nbits: 8,16,32,64
178 address: 1234 or 0x1234
179 value: int value to be written
180 ex. (lldb)writephys 16 0x12345abcd 0x25
181 """
182 if cmd_args == None or len(cmd_args) < 3:
183 print "Invalid arguments.", WritePhys.__doc__
184 else:
185 nbits = ArgumentStringToInt(cmd_args[0])
186 phys_addr = ArgumentStringToInt(cmd_args[1])
187 int_value = ArgumentStringToInt(cmd_args[2])
188 print WritePhysInt(phys_addr, int_value, nbits)
189
190
191 lldb_alias('writephys8', 'writephys 8 ')
192 lldb_alias('writephys16', 'writephys 16 ')
193 lldb_alias('writephys32', 'writephys 32 ')
194 lldb_alias('writephys64', 'writephys 64 ')
195
196
197 def _PT_Step(paddr, index, verbose_level = vSCRIPT):
198 """
199 Step to lower-level page table and print attributes
200 paddr: current page table entry physical address
201 index: current page table entry index (0..511)
202 verbose_level: vHUMAN: print nothing
203 vSCRIPT: print basic information
204 vDETAIL: print basic information and hex table dump
205 returns: (pt_paddr, pt_valid, pt_large)
206 pt_paddr: next level page table entry physical address
207 or null if invalid
208 pt_valid: 1 if $kgm_pt_paddr is valid, 0 if the walk
209 should be aborted
210 pt_large: 1 if kgm_pt_paddr is a page frame address
211 of a large page and not another page table entry
212 """
213 entry_addr = paddr + (8 * index)
214 entry = ReadPhysInt(entry_addr, 64, xnudefines.lcpu_self )
215 out_string = ''
216 if verbose_level >= vDETAIL:
217 for pte_loop in range(0, 512):
218 paddr_tmp = paddr + (8 * pte_loop)
219 out_string += "{0: <#020x}:\t {1: <#020x}\n".format(paddr_tmp, ReadPhysInt(paddr_tmp, 64, xnudefines.lcpu_self))
220 paddr_mask = ~((0xfff<<52) | 0xfff)
221 paddr_large_mask = ~((0xfff<<52) | 0x1fffff)
222 pt_valid = False
223 pt_large = False
224 pt_paddr = 0
225 if verbose_level < vSCRIPT:
226 if entry & 0x1 :
227 pt_valid = True
228 pt_large = False
229 pt_paddr = entry & paddr_mask
230 if entry & (0x1 <<7):
231 pt_large = True
232 pt_paddr = entry & paddr_large_mask
233 else:
234 out_string+= "{0: <#020x}:\n\t{1:#020x}\n\t".format(entry_addr, entry)
235 if entry & 0x1:
236 out_string += " valid"
237 pt_paddr = entry & paddr_mask
238 pt_valid = True
239 else:
240 out_string += " invalid"
241 pt_paddr = 0
242 pt_valid = False
243 if entry & (0x1 << 62):
244 out_string += " compressed"
245 #Stop decoding other bits
246 entry = 0
247 if entry & (0x1 << 1):
248 out_string += " writable"
249 else:
250 out_string += " read-only"
251
252 if entry & (0x1 << 2):
253 out_string += " user"
254 else:
255 out_string += " supervisor"
256
257 if entry & (0x1 << 3):
258 out_string += " PWT"
259
260 if entry & (0x1 << 4):
261 out_string += " PCD"
262
263 if entry & (0x1 << 5):
264 out_string += " accessed"
265
266 if entry & (0x1 << 6):
267 out_string += " dirty"
268
269 if entry & (0x1 << 7):
270 out_string += " large"
271 pt_large = True
272 else:
273 pt_large = False
274
275 if entry & (0x1 << 8):
276 out_string += " global"
277
278 if entry & (0x3 << 9):
279 out_string += " avail:{0:x}".format((entry >> 9) & 0x3)
280
281 if entry & (0x1 << 63):
282 out_string += " noexec"
283 print out_string
284 return (pt_paddr, pt_valid, pt_large)
285
286 def _PT_StepEPT(paddr, index, verbose_level = vSCRIPT):
287 """
288 Step to lower-level page table and print attributes for EPT pmap
289 paddr: current page table entry physical address
290 index: current page table entry index (0..511)
291 verbose_level: vHUMAN: print nothing
292 vSCRIPT: print basic information
293 vDETAIL: print basic information and hex table dump
294 returns: (pt_paddr, pt_valid, pt_large)
295 pt_paddr: next level page table entry physical address
296 or null if invalid
297 pt_valid: 1 if $kgm_pt_paddr is valid, 0 if the walk
298 should be aborted
299 pt_large: 1 if kgm_pt_paddr is a page frame address
300 of a large page and not another page table entry
301 """
302 entry_addr = paddr + (8 * index)
303 entry = ReadPhysInt(entry_addr, 64, xnudefines.lcpu_self )
304 out_string = ''
305 if verbose_level >= vDETAIL:
306 for pte_loop in range(0, 512):
307 paddr_tmp = paddr + (8 * pte_loop)
308 out_string += "{0: <#020x}:\t {1: <#020x}\n".format(paddr_tmp, ReadPhysInt(paddr_tmp, 64, xnudefines.lcpu_self))
309 paddr_mask = ~((0xfff<<52) | 0xfff)
310 paddr_large_mask = ~((0xfff<<52) | 0x1fffff)
311 pt_valid = False
312 pt_large = False
313 pt_paddr = 0
314 if verbose_level < vSCRIPT:
315 if entry & 0x7 :
316 pt_valid = True
317 pt_large = False
318 pt_paddr = entry & paddr_mask
319 if entry & (0x1 <<7):
320 pt_large = True
321 pt_paddr = entry & paddr_large_mask
322 else:
323 out_string+= "{0: <#020x}:\n\t{1:#020x}\n\t".format(entry_addr, entry)
324 if entry & 0x7:
325 out_string += "valid"
326 pt_paddr = entry & paddr_mask
327 pt_valid = True
328 else:
329 out_string += "invalid"
330 pt_paddr = 0
331 pt_valid = False
332 if entry & (0x1 << 62):
333 out_string += " compressed"
334 #Stop decoding other bits
335 entry = 0
336 if entry & 0x1:
337 out_string += " readable"
338 else:
339 out_string += " no read"
340 if entry & (0x1 << 1):
341 out_string += " writable"
342 else:
343 out_string += " no write"
344
345 if entry & (0x1 << 2):
346 out_string += " executable"
347 else:
348 out_string += " no exec"
349
350 ctype = entry & 0x38
351 if ctype == 0x30:
352 out_string += " cache-WB"
353 elif ctype == 0x28:
354 out_string += " cache-WP"
355 elif ctype == 0x20:
356 out_string += " cache-WT"
357 elif ctype == 0x8:
358 out_string += " cache-WC"
359 else:
360 out_string += " cache-NC"
361
362 if (entry & 0x40) == 0x40:
363 out_string += " Ignore-PTA"
364
365 if (entry & 0x100) == 0x100:
366 out_string += " accessed"
367
368 if (entry & 0x200) == 0x200:
369 out_string += " dirty"
370
371 if entry & (0x1 << 7):
372 out_string += " large"
373 pt_large = True
374 else:
375 pt_large = False
376 print out_string
377 return (pt_paddr, pt_valid, pt_large)
378
379 def _PmapL4Walk(pmap_addr_val,vaddr, ept_pmap, verbose_level = vSCRIPT):
380 """ Walk the l4 pmap entry.
381 params: pmap_addr_val - core.value representing kernel data of type pmap_addr_t
382 vaddr : int - virtual address to walk
383 """
384 pt_paddr = unsigned(pmap_addr_val)
385 pt_valid = (unsigned(pmap_addr_val) != 0)
386 pt_large = 0
387 pframe_offset = 0
388 if pt_valid:
389 # Lookup bits 47:39 of linear address in PML4T
390 pt_index = (vaddr >> 39) & 0x1ff
391 pframe_offset = vaddr & 0x7fffffffff
392 if verbose_level > vHUMAN :
393 print "pml4 (index {0:d}):".format(pt_index)
394 if not(ept_pmap):
395 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
396 else:
397 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level)
398 if pt_valid:
399 # Lookup bits 38:30 of the linear address in PDPT
400 pt_index = (vaddr >> 30) & 0x1ff
401 pframe_offset = vaddr & 0x3fffffff
402 if verbose_level > vHUMAN:
403 print "pdpt (index {0:d}):".format(pt_index)
404 if not(ept_pmap):
405 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
406 else:
407 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level)
408 if pt_valid and not pt_large:
409 #Lookup bits 29:21 of the linear address in PDPT
410 pt_index = (vaddr >> 21) & 0x1ff
411 pframe_offset = vaddr & 0x1fffff
412 if verbose_level > vHUMAN:
413 print "pdt (index {0:d}):".format(pt_index)
414 if not(ept_pmap):
415 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
416 else:
417 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level)
418 if pt_valid and not pt_large:
419 #Lookup bits 20:21 of linear address in PT
420 pt_index = (vaddr >> 12) & 0x1ff
421 pframe_offset = vaddr & 0xfff
422 if verbose_level > vHUMAN:
423 print "pt (index {0:d}):".format(pt_index)
424 if not(ept_pmap):
425 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
426 else:
427 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level)
428 paddr = 0
429 paddr_isvalid = False
430 if pt_valid:
431 paddr = pt_paddr + pframe_offset
432 paddr_isvalid = True
433
434 if verbose_level > vHUMAN:
435 if paddr_isvalid:
436 pvalue = ReadPhysInt(paddr, 32, xnudefines.lcpu_self)
437 print "phys {0: <#020x}: {1: <#020x}".format(paddr, pvalue)
438 else:
439 print "no translation"
440
441 return paddr
442
443 def PmapDecodeTTEARM(tte, level, verbose_level):
444 """ Display the bits of an ARM translation table or page table entry
445 in human-readable form.
446 tte: integer value of the TTE/PTE
447 level: translation table level. Valid values are 1 or 2.
448 verbose_level: verbosity. vHUMAN, vSCRIPT, vDETAIL
449 """
450 out_string = ""
451 if level == 1 and (tte & 0x3) == 0x2:
452 if verbose_level < vSCRIPT:
453 return
454
455 #bit [1:0] evaluated in PmapWalkARM
456 # B bit 2
457 b_bit = (tte & 0x4) >> 2
458 # C bit 3
459 c_bit = (tte & 0x8) >> 3
460 #XN bit 4
461 if (tte & 0x10) :
462 out_string += "no-execute"
463 else:
464 out_string += "execute"
465 #Domain bit [8:5] if not supersection
466 if (tte & 0x40000) == 0x0:
467 out_string += " domain ({:d})".format(((tte & 0x1e0) >> 5) )
468 #IMP bit 9
469 out_string += " imp({:d})".format( ((tte & 0x200) >> 9) )
470 # AP bit 15 and [11:10] merged to a single 3 bit value
471 access = ( (tte & 0xc00) >> 10 ) | ((tte & 0x8000) >> 13)
472 out_string += xnudefines.arm_level2_access_strings[access]
473
474 #TEX bit [14:12]
475 tex_bits = ((tte & 0x7000) >> 12)
476 #Print TEX, C , B all together
477 out_string += " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format(
478 1 if (tex_bits & 0x4) else 0,
479 1 if (tex_bits & 0x2) else 0,
480 1 if (tex_bits & 0x1) else 0,
481 c_bit,
482 b_bit
483 )
484 # S bit 16
485 if tte & 0x10000:
486 out_string += " shareable"
487 else:
488 out_string += " not-shareable"
489 # nG bit 17
490 if tte & 0x20000 :
491 out_string += " not-global"
492 else:
493 out_string += " global"
494 # Supersection bit 18
495 if tte & 0x40000:
496 out_string += " supersection"
497 else:
498 out_string += " section"
499 #NS bit 19
500 if tte & 0x80000 :
501 out_string += " no-secure"
502 else:
503 out_string += " secure"
504
505 elif level == 1 and (tte & 0x3) == 0x1:
506
507 if verbose_level >= vSCRIPT:
508 # bit [1:0] evaluated in PmapWalkARM
509 # NS bit 3
510 if tte & 0x8:
511 out_string += ' no-secure'
512 else:
513 out_string += ' secure'
514 #Domain bit [8:5]
515 out_string += " domain({:d})".format(((tte & 0x1e0) >> 5))
516 # IMP bit 9
517 out_string += " imp({:d})".format( ((tte & 0x200) >> 9))
518 out_string += "\n"
519
520 elif level == 2:
521 pte = tte
522 if verbose_level >= vSCRIPT:
523 if (pte & 0x3) == 0x0:
524 out_string += " invalid"
525 else:
526 if (pte & 0x3) == 0x1:
527 out_string += " large"
528 # XN bit 15
529 if pte & 0x8000 == 0x8000:
530 out_string+= " no-execute"
531 else:
532 out_string += " execute"
533 else:
534 out_string += " small"
535 # XN bit 0
536 if (pte & 0x1) == 0x01:
537 out_string += " no-execute"
538 else:
539 out_string += " execute"
540 # B bit 2
541 b_bit = (pte & 0x4) >> 2
542 c_bit = (pte & 0x8) >> 3
543 # AP bit 9 and [5:4], merged to a single 3-bit value
544 access = (pte & 0x30) >> 4 | (pte & 0x200) >> 7
545 out_string += xnudefines.arm_level2_access_strings[access]
546
547 #TEX bit [14:12] for large, [8:6] for small
548 tex_bits = ((pte & 0x1c0) >> 6)
549 if (pte & 0x3) == 0x1:
550 tex_bits = ((pte & 0x7000) >> 12)
551
552 # Print TEX, C , B alltogether
553 out_string += " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format(
554 1 if (tex_bits & 0x4) else 0,
555 1 if (tex_bits & 0x2) else 0,
556 1 if (tex_bits & 0x1) else 0,
557 c_bit,
558 b_bit
559 )
560 # S bit 10
561 if pte & 0x400 :
562 out_string += " shareable"
563 else:
564 out_string += " not-shareable"
565
566 # nG bit 11
567 if pte & 0x800:
568 out_string += " not-global"
569 else:
570 out_string += " global"
571
572 print out_string
573
574
575 def _PmapWalkARMLevel1Section(tte, vaddr, verbose_level = vSCRIPT):
576 paddr = 0
577 #Supersection or just section?
578 if (tte & 0x40000) == 0x40000:
579 paddr = ( (tte & 0xFF000000) | (vaddr & 0x00FFFFFF) )
580 else:
581 paddr = ( (tte & 0xFFF00000) | (vaddr & 0x000FFFFF) )
582
583 if verbose_level >= vSCRIPT:
584 print "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte), tte),
585
586 PmapDecodeTTEARM(tte, 1, verbose_level)
587
588 return paddr
589
590
591
592 def _PmapWalkARMLevel2(tte, vaddr, verbose_level = vSCRIPT):
593 """ Pmap walk the level 2 tte.
594 params:
595 tte - value object
596 vaddr - int
597 returns: str - description of the tte + additional informaiton based on verbose_level
598 """
599 pte_base = kern.PhysToKernelVirt(tte & 0xFFFFFC00)
600 pte_index = (vaddr >> 12) & 0xFF
601 pte_base_val = kern.GetValueFromAddress(pte_base, 'pt_entry_t *')
602 pte = pte_base_val[pte_index]
603
604 paddr = 0
605 if pte & 0x2:
606 paddr = (unsigned(pte) & 0xFFFFF000) | (vaddr & 0xFFF)
607
608 if verbose_level >= vSCRIPT:
609 print "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte), tte),
610
611 PmapDecodeTTEARM(tte, 1, verbose_level)
612 if verbose_level >= vSCRIPT:
613 print "second-level table (index {:d}):".format(pte_index)
614 if verbose_level >= vDETAIL:
615 for i in range(256):
616 tmp = pte_base_val[i]
617 print "{0: <#020x}:\t{1: <#020x}".format(addressof(tmp), unsigned(tmp))
618
619 if verbose_level >= vSCRIPT:
620 print " {0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(pte), unsigned(pte)),
621
622 PmapDecodeTTEARM(pte, 2, verbose_level)
623
624 return paddr
625 #end of level 2 walking of arm
626
627
628 def PmapWalkARM(pmap, vaddr, verbose_level = vHUMAN):
629 """ Pmap walking for ARM kernel.
630 params:
631 pmapval: core.value - representing pmap_t in kernel
632 vaddr: int - integer representing virtual address to walk
633 """
634 paddr = 0
635 # shift by TTESHIFT (20) to get tte index
636 # Assume all L1 indexing starts at VA 0...for our purposes it does,
637 # as that's where all user pmaps start, and the kernel pmap contains
638 # 4 L1 pages (the lower 2 of which are unused after bootstrap)
639 tte_index = vaddr >> 20
640 tte = pmap.tte[tte_index]
641 if verbose_level >= vSCRIPT:
642 print "First-level table (index {:d}):".format(tte_index)
643 if verbose_level >= vDETAIL:
644 for i in range(0, pmap.tte_index_max):
645 ptr = unsigned(addressof(pmap.tte[i]))
646 val = unsigned(pmap.tte[i])
647 print "{0: <#020x}:\t {1: <#020x}".format(ptr, val)
648 if (tte & 0x3) == 0x1:
649 paddr = _PmapWalkARMLevel2(tte, vaddr, verbose_level)
650 elif (tte & 0x3) == 0x2 :
651 paddr = _PmapWalkARMLevel1Section(tte, vaddr, verbose_level)
652 else:
653 paddr = 0
654 if verbose_level >= vSCRIPT:
655 print "Invalid First-Level Translation Table Entry: {0: #020x}".format(tte)
656
657 if verbose_level >= vHUMAN:
658 if paddr:
659 print "Translation of {:#x} is {:#x}.".format(vaddr, paddr)
660 else:
661 print "(no translation)"
662
663 return paddr
664
665 def PmapWalkX86_64(pmapval, vaddr, verbose_level = vSCRIPT):
666 """
667 params: pmapval - core.value representing pmap_t in kernel
668 vaddr: int - int representing virtual address to walk
669 """
670 if pmapval.pm_cr3 != 0:
671 if verbose_level > vHUMAN:
672 print "Using normal Intel PMAP from pm_cr3\n"
673 return _PmapL4Walk(pmapval.pm_cr3, vaddr, 0, config['verbosity'])
674 else:
675 if verbose_level > vHUMAN:
676 print "Using EPT pmap from pm_eptp\n"
677 return _PmapL4Walk(pmapval.pm_eptp, vaddr, 1, config['verbosity'])
678
679 def assert_64bit(val):
680 assert(val < 2**64)
681
682 ARM64_TTE_SIZE = 8
683 ARM64_TTE_SHIFT = 3
684 ARM64_VMADDR_BITS = 48
685
686 def PmapBlockOffsetMaskARM64(level):
687 assert level >= 1 and level <= 3
688 page_size = kern.globals.arm_hardware_page_size
689 ttentries = (page_size / ARM64_TTE_SIZE)
690 return page_size * (ttentries ** (3 - level)) - 1
691
692 def PmapBlockBaseMaskARM64(level):
693 assert level >= 1 and level <= 3
694 page_size = kern.globals.arm_hardware_page_size
695 return ((1 << ARM64_VMADDR_BITS) - 1) & ~PmapBlockOffsetMaskARM64(level)
696
697 def PmapIndexMaskARM64(level):
698 assert level >= 1 and level <= 3
699 page_size = kern.globals.arm_hardware_page_size
700 ttentries = (page_size / ARM64_TTE_SIZE)
701 return page_size * (ttentries ** (3 - level) * (ttentries - 1))
702
703 def PmapIndexDivideARM64(level):
704 assert level >= 1 and level <= 3
705 page_size = kern.globals.arm_hardware_page_size
706 ttentries = (page_size / ARM64_TTE_SIZE)
707 return page_size * (ttentries ** (3 - level))
708
709 def PmapTTnIndexARM64(vaddr, level):
710 assert(type(vaddr) in (long, int))
711 assert_64bit(vaddr)
712
713 return (vaddr & PmapIndexMaskARM64(level)) // PmapIndexDivideARM64(level)
714
715 def PmapDecodeTTEARM64(tte, level):
716 """ Display the bits of an ARM64 translation table or page table entry
717 in human-readable form.
718 tte: integer value of the TTE/PTE
719 level: translation table level. Valid values are 1, 2, or 3.
720 """
721 assert(type(tte) == long)
722 assert(type(level) == int)
723 assert_64bit(tte)
724
725 if tte & 0x1 == 0x1:
726 if (tte & 0x2 == 0x2) and (level != 0x3):
727 print "Type = Table pointer."
728 print "Table addr = {:#x}.".format(tte & 0xfffffffff000)
729 print "PXN = {:#x}.".format((tte >> 59) & 0x1)
730 print "XN = {:#x}.".format((tte >> 60) & 0x1)
731 print "AP = {:#x}.".format((tte >> 61) & 0x3)
732 print "NS = {:#x}".format(tte >> 63)
733 else:
734 print "Type = Block."
735 print "AttrIdx = {:#x}.".format((tte >> 2) & 0x7)
736 print "NS = {:#x}.".format((tte >> 5) & 0x1)
737 print "AP = {:#x}.".format((tte >> 6) & 0x3)
738 print "SH = {:#x}.".format((tte >> 8) & 0x3)
739 print "AF = {:#x}.".format((tte >> 10) & 0x1)
740 print "nG = {:#x}.".format((tte >> 11) & 0x1)
741 print "HINT = {:#x}.".format((tte >> 52) & 0x1)
742 print "PXN = {:#x}.".format((tte >> 53) & 0x1)
743 print "XN = {:#x}.".format((tte >> 54) & 0x1)
744 print "SW Use = {:#x}.".format((tte >> 55) & 0xf)
745 else:
746 print "Invalid."
747
748 return
749
750 def PmapWalkARM64(pmap, vaddr, verbose_level = vHUMAN):
751 assert(type(pmap) == core.cvalue.value)
752 assert(type(vaddr) in (long, int))
753 page_size = kern.globals.arm_hardware_page_size
754 page_offset_mask = (page_size - 1)
755 page_base_mask = ((1 << ARM64_VMADDR_BITS) - 1) & (~page_offset_mask)
756
757 assert_64bit(vaddr)
758 paddr = -1
759
760 tt0_index = 0
761 tt1_index = PmapTTnIndexARM64(vaddr, 1)
762 tt2_index = PmapTTnIndexARM64(vaddr, 2)
763 tt3_index = PmapTTnIndexARM64(vaddr, 3)
764
765 # The pmap starts at a page tabel level that is defined by register
766 # values; the kernel exports the root level for LLDB
767 level = kern.globals.arm64_root_pgtable_level
768 assert(level <= 3)
769
770 if level == 0:
771 root_tt_index = tt0_index
772 elif level == 1:
773 root_tt_index = tt1_index
774 elif level == 2:
775 root_tt_index = tt2_index
776 elif level == 3:
777 root_tt_index = tt3_index
778
779 # If the root of the page table is not a full page, we need to
780 # truncate the index
781 root_tt_index = root_tt_index % unsigned(kern.globals.arm64_root_pgtable_num_ttes)
782
783 tte = long(unsigned(pmap.tte[root_tt_index]))
784 assert(type(tte) == long)
785 assert_64bit(tte)
786
787 while (True):
788 if (level == 0):
789 # L0
790 # This is unsupported at the moment, as no kernel configurations use L0
791 assert(False)
792
793 elif (level == 1):
794 # L1
795 if verbose_level >= vSCRIPT:
796 print "L1 entry: {:#x}".format(tte)
797 if verbose_level >= vDETAIL:
798 PmapDecodeTTEARM64(tte, 1)
799
800 if tte & 0x1 == 0x1:
801 # Check for L1 block entry
802 if tte & 0x2 == 0x0:
803 # Handle L1 block entry
804 paddr = tte & PmapBlockBaseMaskARM64(1)
805 paddr = paddr | (vaddr & PmapBlockOffsetMaskARM64(1))
806 print "phys: {:#x}".format(paddr)
807 break
808 else:
809 # Handle L1 table entry
810 l2_phys = (tte & page_base_mask) + (ARM64_TTE_SIZE * tt2_index)
811 assert(type(l2_phys) == long)
812
813 l2_virt = kern.PhysToKernelVirt(l2_phys)
814 assert(type(l2_virt) == long)
815
816 if verbose_level >= vDETAIL:
817 print "L2 physical address: {:#x}. L2 virtual address: {:#x}".format(l2_phys, l2_virt)
818
819 ttep = kern.GetValueFromAddress(l2_virt, "tt_entry_t*")
820 tte = long(unsigned(dereference(ttep)))
821 assert(type(tte) == long)
822 elif verbose_level >= vHUMAN:
823 print "L1 entry invalid: {:#x}\n".format(tte)
824
825 elif (level == 2):
826 # L2
827 if verbose_level >= vSCRIPT:
828 print "L2 entry: {:#0x}".format(tte)
829 if verbose_level >= vDETAIL:
830 PmapDecodeTTEARM64(tte, 2)
831
832 if tte & 0x1 == 0x1:
833 # Check for L2 block entry
834 if tte & 0x2 == 0x0:
835 # Handle L2 block entry
836 paddr = tte & PmapBlockBaseMaskARM64(2)
837 paddr = paddr | (vaddr & PmapBlockOffsetMaskARM64(2))
838 break
839 else:
840 # Handle L2 table entry
841 l3_phys = (tte & page_base_mask) + (ARM64_TTE_SIZE * tt3_index)
842 assert(type(l3_phys) == long)
843
844 l3_virt = kern.PhysToKernelVirt(l3_phys)
845 assert(type(l3_virt) == long)
846
847 if verbose_level >= vDETAIL:
848 print "L3 physical address: {:#x}. L3 virtual address: {:#x}".format(l3_phys, l3_virt)
849
850 ttep = kern.GetValueFromAddress(l3_virt, "tt_entry_t*")
851 tte = long(unsigned(dereference(ttep)))
852 assert(type(tte) == long)
853 elif verbose_level >= vHUMAN: # tte & 0x1 == 0x1
854 print "L2 entry invalid: {:#x}\n".format(tte)
855
856 elif (level == 3):
857 # L3
858 if verbose_level >= vSCRIPT:
859 print "L3 entry: {:#0x}".format(tte)
860 if verbose_level >= vDETAIL:
861 PmapDecodeTTEARM64(tte, 3)
862
863 if tte & 0x3 == 0x3:
864 paddr = tte & page_base_mask
865 paddr = paddr | (vaddr & page_offset_mask)
866 elif verbose_level >= vHUMAN:
867 print "L3 entry invalid: {:#x}\n".format(tte)
868
869 # This was the leaf page table page for this request; we're done
870 break
871
872 # We've parsed one level, so go to the next level
873 assert(level <= 3)
874 level = level + 1
875
876 if verbose_level >= vHUMAN:
877 if paddr:
878 print "Translation of {:#x} is {:#x}.".format(vaddr, paddr)
879 else:
880 print "(no translation)"
881
882 return paddr
883
884 def PmapWalk(pmap, vaddr, verbose_level = vHUMAN):
885 if kern.arch == 'x86_64':
886 return PmapWalkX86_64(pmap, vaddr, verbose_level)
887 elif kern.arch == 'arm':
888 return PmapWalkARM(pmap, vaddr, verbose_level)
889 elif kern.arch.startswith('arm64'):
890 return PmapWalkARM64(pmap, vaddr, verbose_level)
891 else:
892 raise NotImplementedError("PmapWalk does not support {0}".format(kern.arch))
893
894 @lldb_command('pmap_walk')
895 def PmapWalkHelper(cmd_args=None):
896 """ Perform a page-table walk in <pmap> for <virtual_address>.
897 Syntax: (lldb) pmap_walk <pmap> <virtual_address> [-v] [-e]
898 Multiple -v's can be specified for increased verbosity
899 """
900 if cmd_args == None or len(cmd_args) < 2:
901 raise ArgumentError("Too few arguments to pmap_walk.")
902
903 pmap = kern.GetValueAsType(cmd_args[0], 'pmap_t')
904 addr = unsigned(kern.GetValueFromAddress(cmd_args[1], 'void *'))
905 PmapWalk(pmap, addr, config['verbosity'])
906 return
907
908 @lldb_command('decode_tte')
909 def DecodeTTE(cmd_args=None):
910 """ Decode the bits in the TTE/PTE value specified <tte_val> for translation level <level>
911 Syntax: (lldb) decode_tte <tte_val> <level>
912 """
913 if cmd_args == None or len(cmd_args) < 2:
914 raise ArgumentError("Too few arguments to decode_tte.")
915 if kern.arch == 'arm':
916 PmapDecodeTTEARM(kern.GetValueFromAddress(cmd_args[0], "unsigned long"), ArgumentStringToInt(cmd_args[1]), vSCRIPT)
917 elif kern.arch.startswith('arm64'):
918 PmapDecodeTTEARM64(long(kern.GetValueFromAddress(cmd_args[0], "unsigned long")), ArgumentStringToInt(cmd_args[1]))
919 else:
920 raise NotImplementedError("decode_tte does not support {0}".format(kern.arch))
921
922
923 PVH_HIGH_FLAGS_ARM64 = (1 << 62) | (1 << 61) | (1 << 60) | (1 << 59)
924 PVH_HIGH_FLAGS_ARM32 = (1 << 31)
925
926 def PVWalkARM(pa):
927 """ Walk a physical-to-virtual reverse mapping list maintained by the arm pmap
928 pa: physical address (NOT page number). Does not need to be page-aligned
929 """
930 vm_first_phys = unsigned(kern.globals.vm_first_phys)
931 vm_last_phys = unsigned(kern.globals.vm_last_phys)
932 if pa < vm_first_phys or pa >= vm_last_phys:
933 raise ArgumentError("PA {:#x} is outside range of managed physical addresses: [{:#x}, {:#x})".format(pa, vm_first_phys, vm_last_phys))
934 page_size = kern.globals.page_size
935 pn = (pa - unsigned(kern.globals.vm_first_phys)) / page_size
936 pvh = unsigned(kern.globals.pv_head_table[pn])
937 pvh_type = pvh & 0x3
938 print "PVH raw value: ({:#x})".format(pvh)
939 if kern.arch.startswith('arm64'):
940 iommu_flag = 0x4
941 iommu_table_flag = 1 << 63
942 pvh = pvh | PVH_HIGH_FLAGS_ARM64
943 else:
944 iommu_flag = 0
945 iommu_table_flag = 0
946 pvh = pvh | PVH_HIGH_FLAGS_ARM32
947 if pvh_type == 0:
948 print "PVH type: NULL"
949 return
950 elif pvh_type == 3:
951 print "PVH type: page-table descriptor ({:#x})".format(pvh & ~0x3)
952 return
953 elif pvh_type == 2:
954 ptep = pvh & ~0x3
955 pte_str = ''
956 print "PVH type: single PTE"
957 if ptep & iommu_flag:
958 ptep = ptep & ~iommu_flag
959 if ptep & iommu_table_flag:
960 pte_str = ' (IOMMU table), entry'
961 else:
962 pte_str = ' (IOMMU state), descriptor'
963 ptep = ptep | iommu_table_flag
964 print "PTE {:#x}{:s}: {:#x}".format(ptep, pte_str, dereference(kern.GetValueFromAddress(ptep, 'pt_entry_t *')))
965 elif pvh_type == 1:
966 pvep = pvh & ~0x3
967 print "PVH type: PTE list"
968 while pvep != 0:
969 pve = kern.GetValueFromAddress(pvep, "pv_entry_t *")
970 if unsigned(pve.pve_next) & 0x1:
971 pve_str = ' (alt acct) '
972 else:
973 pve_str = ''
974 current_pvep = pvep
975 pvep = unsigned(pve.pve_next) & ~0x1
976 ptep = unsigned(pve.pve_ptep) & ~0x3
977 if ptep & iommu_flag:
978 ptep = ptep & ~iommu_flag
979 if ptep & iommu_table_flag:
980 pve_str = ' (IOMMU table), entry'
981 else:
982 pve_str = ' (IOMMU state), descriptor'
983 ptep = ptep | iommu_table_flag
984 print "PVE {:#x}, PTE {:#x}{:s}: {:#x}".format(current_pvep, ptep, pve_str, dereference(kern.GetValueFromAddress(ptep, 'pt_entry_t *')))
985
986 @lldb_command('pv_walk')
987 def PVWalk(cmd_args=None):
988 """ Show mappings for <physical_address> tracked in the PV list.
989 Syntax: (lldb) pv_walk <physical_address>
990 """
991 if cmd_args == None or len(cmd_args) < 1:
992 raise ArgumentError("Too few arguments to pv_walk.")
993 if not kern.arch.startswith('arm'):
994 raise NotImplementedError("pv_walk does not support {0}".format(kern.arch))
995 PVWalkARM(kern.GetValueFromAddress(cmd_args[0], 'unsigned long'))
996
997 @lldb_command('kvtophys')
998 def KVToPhys(cmd_args=None):
999 """ Translate a kernel virtual address to the corresponding physical address.
1000 Assumes the virtual address falls within the kernel static region.
1001 Syntax: (lldb) kvtophys <kernel virtual address>
1002 """
1003 if cmd_args == None or len(cmd_args) < 1:
1004 raise ArgumentError("Too few arguments to kvtophys.")
1005 if kern.arch.startswith('arm'):
1006 print "{:#x}".format(KVToPhysARM(long(unsigned(kern.GetValueFromAddress(cmd_args[0], 'unsigned long')))))
1007 elif kern.arch == 'x86_64':
1008 print "{:#x}".format(long(unsigned(kern.GetValueFromAddress(cmd_args[0], 'unsigned long'))) - unsigned(kern.globals.physmap_base))
1009
1010 @lldb_command('phystokv')
1011 def PhysToKV(cmd_args=None):
1012 """ Translate a physical address to the corresponding static kernel virtual address.
1013 Assumes the physical address corresponds to managed DRAM.
1014 Syntax: (lldb) phystokv <physical address>
1015 """
1016 if cmd_args == None or len(cmd_args) < 1:
1017 raise ArgumentError("Too few arguments to phystokv.")
1018 print "{:#x}".format(kern.PhysToKernelVirt(long(unsigned(kern.GetValueFromAddress(cmd_args[0], 'unsigned long')))))
1019
1020 def KVToPhysARM(addr):
1021 if kern.arch.startswith('arm64'):
1022 ptov_table = kern.globals.ptov_table
1023 for i in range(0, kern.globals.ptov_index):
1024 if (addr >= long(unsigned(ptov_table[i].va))) and (addr < (long(unsigned(ptov_table[i].va)) + long(unsigned(ptov_table[i].len)))):
1025 return (addr - long(unsigned(ptov_table[i].va)) + long(unsigned(ptov_table[i].pa)))
1026 return (addr - unsigned(kern.globals.gVirtBase) + unsigned(kern.globals.gPhysBase))
1027
1028 def ShowPTEARM(pte):
1029 """ Display vital information about an ARM page table entry
1030 pte: kernel virtual address of the PTE. Should be L3 PTE. May also work with L2 TTEs for certain devices.
1031 """
1032 page_size = kern.globals.arm_hardware_page_size
1033 pn = (KVToPhysARM(pte) - unsigned(kern.globals.vm_first_phys)) / page_size
1034 pvh = unsigned(kern.globals.pv_head_table[pn])
1035 if kern.arch.startswith('arm64'):
1036 pvh = pvh | PVH_HIGH_FLAGS_ARM64
1037 else:
1038 pvh = pvh | PVH_HIGH_FLAGS_ARM32
1039 pvh_type = pvh & 0x3
1040 if pvh_type != 0x3:
1041 raise ValueError("PV head {:#x} does not correspond to a page-table descriptor".format(pvh))
1042 ptd = kern.GetValueFromAddress(pvh & ~0x3, 'pt_desc_t *')
1043 print "descriptor: {:#x}".format(ptd)
1044 print "pmap: {:#x}".format(ptd.pmap)
1045 pt_index = (pte % kern.globals.page_size) / page_size
1046 pte_pgoff = pte % page_size
1047 if kern.arch.startswith('arm64'):
1048 pte_pgoff = pte_pgoff / 8
1049 nttes = page_size / 8
1050 else:
1051 pte_pgoff = pte_pgoff / 4
1052 nttes = page_size / 4
1053 if ptd.pt_cnt[pt_index].refcnt == 0x4000:
1054 level = 2
1055 granule = nttes * page_size
1056 else:
1057 level = 3
1058 granule = page_size
1059 print "maps VA: {:#x}".format(long(unsigned(ptd.pt_map[pt_index].va)) + (pte_pgoff * granule))
1060 pteval = long(unsigned(dereference(kern.GetValueFromAddress(unsigned(pte), 'pt_entry_t *'))))
1061 print "value: {:#x}".format(pteval)
1062 if kern.arch.startswith('arm64'):
1063 print "level: {:d}".format(level)
1064 PmapDecodeTTEARM64(pteval, level)
1065 elif kern.arch == 'arm':
1066 PmapDecodeTTEARM(pteval, 2, vSCRIPT)
1067
1068 @lldb_command('showpte')
1069 def ShowPTE(cmd_args=None):
1070 """ Display vital information about the page table entry at VA <pte>
1071 Syntax: (lldb) showpte <pte_va>
1072 """
1073 if cmd_args == None or len(cmd_args) < 1:
1074 raise ArgumentError("Too few arguments to showpte.")
1075 if not kern.arch.startswith('arm'):
1076 raise NotImplementedError("showpte does not support {0}".format(kern.arch))
1077 ShowPTEARM(kern.GetValueFromAddress(cmd_args[0], 'unsigned long'))
1078
1079 def FindMappingAtLevelARM(pmap, tt, nttes, level, action):
1080 """ Perform the specified action for all valid mappings in an ARM translation table
1081 pmap: owner of the translation table
1082 tt: translation table or page table
1083 nttes: number of entries in tt
1084 level: translation table level, 1 or 2
1085 action: callback for each valid TTE
1086 """
1087 for i in range(nttes):
1088 try:
1089 tte = tt[i]
1090 if level == 1:
1091 if tte & 0x3 == 0x1:
1092 type = 'table'
1093 granule = 1024
1094 paddr = tte & 0xFFFFFC00
1095 elif tte & 0x3 == 0x2:
1096 type = 'block'
1097 if (tte & 0x40000) == 0x40000:
1098 granule = 1 << 24
1099 paddr = tte & 0xFF000000
1100 else:
1101 granule = 1 << 20
1102 paddr = tte & 0xFFF00000
1103 else:
1104 continue
1105 elif (tte & 0x3) == 0x1:
1106 type = 'entry'
1107 granule = 1 << 16
1108 paddr = tte & 0xFFFF0000
1109 elif (tte & 0x3) != 0:
1110 type = 'entry'
1111 granule = 1 << 12
1112 paddr = tte & 0xFFFFF000
1113 else:
1114 continue
1115 action(pmap, level, type, addressof(tt[i]), paddr, granule)
1116 if level == 1 and (tte & 0x3) == 0x1:
1117 tt_next = kern.GetValueFromAddress(kern.PhysToKernelVirt(paddr), 'tt_entry_t *')
1118 FindMappingAtLevelARM(pmap, tt_next, granule / 4, level + 1, action)
1119 except Exception as exc:
1120 print "Unable to access tte {:#x}".format(unsigned(addressof(tt[i])))
1121
1122 def FindMappingAtLevelARM64(pmap, tt, nttes, level, action):
1123 """ Perform the specified action for all valid mappings in an ARM64 translation table
1124 pmap: owner of the translation table
1125 tt: translation table or page table
1126 nttes: number of entries in tt
1127 level: translation table level, 1 2 or 3
1128 action: callback for each valid TTE
1129 """
1130 page_size = kern.globals.arm_hardware_page_size
1131 page_offset_mask = (page_size - 1)
1132 page_base_mask = ((1 << ARM64_VMADDR_BITS) - 1) & (~page_offset_mask)
1133 for i in range(nttes):
1134 try:
1135 tte = tt[i]
1136 if tte & 0x1 == 0x1:
1137 if tte & 0x2 == 0x2:
1138 if level < 3:
1139 type = 'table'
1140 else:
1141 type = 'entry'
1142 granule = page_size
1143 paddr = tte & page_base_mask
1144 elif level < 3:
1145 type = 'block'
1146 granule = PmapBlockOffsetMaskARM64(level) + 1
1147 paddr = tte & PmapBlockBaseMaskARM64(level)
1148 else:
1149 continue
1150 action(pmap, level, type, addressof(tt[i]), paddr, granule)
1151 if level < 3 and (tte & 0x2 == 0x2):
1152 tt_next = kern.GetValueFromAddress(kern.PhysToKernelVirt(paddr), 'tt_entry_t *')
1153 FindMappingAtLevelARM64(pmap, tt_next, granule / ARM64_TTE_SIZE, level + 1, action)
1154 except Exception as exc:
1155 print "Unable to access tte {:#x}".format(unsigned(addressof(tt[i])))
1156
1157 def ScanPageTables(action, targetPmap=None):
1158 """ Perform the specified action for all valid mappings in all page tables,
1159 optionally restricted to a single pmap.
1160 pmap: pmap whose page table should be scanned. If None, all pmaps on system will be scanned.
1161 """
1162 print "Scanning all available translation tables. This may take a long time..."
1163 def ScanPmap(pmap, action):
1164 if kern.arch.startswith('arm64'):
1165 granule = kern.globals.arm64_root_pgtable_num_ttes * 8
1166 elif kern.arch == 'arm':
1167 granule = pmap.tte_index_max * 4
1168 action(pmap, 1, 'root', pmap.tte, unsigned(pmap.ttep), granule)
1169 if kern.arch.startswith('arm64'):
1170 FindMappingAtLevelARM64(pmap, pmap.tte, kern.globals.arm64_root_pgtable_num_ttes, kern.globals.arm64_root_pgtable_level, action)
1171 elif kern.arch == 'arm':
1172 FindMappingAtLevelARM(pmap, pmap.tte, pmap.tte_index_max, 1, action)
1173
1174 if targetPmap is not None:
1175 ScanPmap(kern.GetValueFromAddress(targetPmap, 'pmap_t'), action)
1176 else:
1177 for pmap in IterateQueue(kern.globals.map_pmap_list, 'pmap_t', 'pmaps'):
1178 ScanPmap(pmap, action)
1179
1180 @lldb_command('showallmappings')
1181 def ShowAllMappings(cmd_args=None):
1182 """ Find and display all available mappings on the system for
1183 <physical_address>. Optionally only searches the pmap
1184 specified by [<pmap>]
1185 Syntax: (lldb) showallmappings <physical_address> [<pmap>]
1186 WARNING: this macro can take a long time (up to 30min.) to complete!
1187 """
1188 if cmd_args == None or len(cmd_args) < 1:
1189 raise ArgumentError("Too few arguments to showallmappings.")
1190 if not kern.arch.startswith('arm'):
1191 raise NotImplementedError("showallmappings does not support {0}".format(kern.arch))
1192 pa = kern.GetValueFromAddress(cmd_args[0], 'unsigned long')
1193 targetPmap = None
1194 if len(cmd_args) > 1:
1195 targetPmap = cmd_args[1]
1196 def printMatchedMapping(pmap, level, type, tte, paddr, granule):
1197 if paddr <= pa < (paddr + granule):
1198 print "pmap: {:#x}: L{:d} {:s} at {:#x}: [{:#x}, {:#x})".format(pmap, level, type, unsigned(tte), paddr, paddr + granule)
1199 ScanPageTables(printMatchedMapping, targetPmap)
1200
1201 def checkPVList(pmap, level, type, tte, paddr, granule):
1202 """ Checks an ARM physical-to-virtual mapping list for consistency errors.
1203 pmap: owner of the translation table
1204 level: translation table level. PV lists will only be checked for L2 (arm32) or L3 (arm64) tables.
1205 type: unused
1206 tte: KVA of PTE to check for presence in PV list. If None, presence check will be skipped.
1207 paddr: physical address whose PV list should be checked. Need not be page-aligned.
1208 granule: unused
1209 """
1210 vm_first_phys = unsigned(kern.globals.vm_first_phys)
1211 vm_last_phys = unsigned(kern.globals.vm_last_phys)
1212 page_size = kern.globals.page_size
1213 if kern.arch.startswith('arm64'):
1214 page_offset_mask = (page_size - 1)
1215 page_base_mask = ((1 << ARM64_VMADDR_BITS) - 1) & (~page_offset_mask)
1216 paddr = paddr & page_base_mask
1217 max_level = 3
1218 pvh_set_bits = PVH_HIGH_FLAGS_ARM64
1219 elif kern.arch == 'arm':
1220 page_base_mask = 0xFFFFF000
1221 paddr = paddr & page_base_mask
1222 max_level = 2
1223 pvh_set_bits = PVH_HIGH_FLAGS_ARM32
1224 if level < max_level or paddr < vm_first_phys or paddr >= vm_last_phys:
1225 return
1226 pn = (paddr - vm_first_phys) / page_size
1227 pvh = unsigned(kern.globals.pv_head_table[pn]) | pvh_set_bits
1228 pvh_type = pvh & 0x3
1229 if pmap is not None:
1230 pmap_str = "pmap: {:#x}: ".format(pmap)
1231 else:
1232 pmap_str = ''
1233 if tte is not None:
1234 tte_str = "pte {:#x} ({:#x}): ".format(unsigned(tte), paddr)
1235 else:
1236 tte_str = "paddr {:#x}: ".format(paddr)
1237 if pvh_type == 0 or pvh_type == 3:
1238 print "{:s}{:s}unexpected PVH type {:d}".format(pmap_str, tte_str, pvh_type)
1239 elif pvh_type == 2:
1240 ptep = pvh & ~0x3
1241 if tte is not None and ptep != unsigned(tte):
1242 print "{:s}{:s}PVH mismatch ({:#x})".format(pmap_str, tte_str, ptep)
1243 try:
1244 pte = long(unsigned(dereference(kern.GetValueFromAddress(ptep, 'pt_entry_t *')))) & page_base_mask
1245 if (pte != paddr):
1246 print "{:s}{:s}PVH {:#x} maps wrong page ({:#x}) ".format(pmap_str, tte_str, ptep, pte)
1247 except Exception as exc:
1248 print "{:s}{:s}Unable to read PVH {:#x}".format(pmap_str, tte_str, ptep)
1249 elif pvh_type == 1:
1250 pvep = pvh & ~0x3
1251 tte_match = False
1252 while pvep != 0:
1253 pve = kern.GetValueFromAddress(pvep, "pv_entry_t *")
1254 pvep = unsigned(pve.pve_next) & ~0x1
1255 ptep = unsigned(pve.pve_ptep) & ~0x3
1256 if tte is not None and ptep == unsigned(tte):
1257 tte_match = True
1258 try:
1259 pte = long(unsigned(dereference(kern.GetValueFromAddress(ptep, 'pt_entry_t *')))) & page_base_mask
1260 if (pte != paddr):
1261 print "{:s}{:s}PVE {:#x} maps wrong page ({:#x}) ".format(pmap_str, tte_str, ptep, pte)
1262 except Exception as exc:
1263 print "{:s}{:s}Unable to read PVE {:#x}".format(pmap_str, tte_str, ptep)
1264 if tte is not None and not tte_match:
1265 print "{:s}{:s}not found in PV list".format(pmap_str, tte_str, paddr)
1266
1267 @lldb_command('pv_check', 'P')
1268 def PVCheck(cmd_args=None, cmd_options={}):
1269 """ Check the physical-to-virtual mapping for a given PTE or physical address
1270 Syntax: (lldb) pv_check <addr> [-p]
1271 -P : Interpret <addr> as a physical address rather than a PTE
1272 """
1273 if cmd_args == None or len(cmd_args) < 1:
1274 raise ArgumentError("Too few arguments to pv_check.")
1275 if kern.arch == 'arm':
1276 level = 2
1277 elif kern.arch.startswith('arm64'):
1278 level = 3
1279 else:
1280 raise NotImplementedError("showallmappings does not support {0}".format(kern.arch))
1281 if "-P" in cmd_options:
1282 pte = None
1283 pa = long(unsigned(kern.GetValueFromAddress(cmd_args[0], "unsigned long")))
1284 else:
1285 pte = kern.GetValueFromAddress(cmd_args[0], 'pt_entry_t *')
1286 pa = long(unsigned(dereference(pte)))
1287 checkPVList(None, level, None, pte, pa, None)
1288
1289 @lldb_command('check_pmaps')
1290 def CheckPmapIntegrity(cmd_args=None):
1291 """ Performs a system-wide integrity check of all PTEs and associated PV lists.
1292 Optionally only checks the pmap specified by [<pmap>]
1293 Syntax: (lldb) check_pmaps [<pmap>]
1294 WARNING: this macro can take a HUGE amount of time (several hours) if you do not
1295 specify [pmap] to limit it to a single pmap. It will also give false positives
1296 for kernel_pmap, as we do not create PV entries for static kernel mappings on ARM.
1297 Use of this macro without the [<pmap>] argument is heavily discouraged.
1298 """
1299 if not kern.arch.startswith('arm'):
1300 raise NotImplementedError("showallmappings does not support {0}".format(kern.arch))
1301 targetPmap = None
1302 if len(cmd_args) > 0:
1303 targetPmap = cmd_args[0]
1304 ScanPageTables(checkPVList, targetPmap)
1305
1306 @lldb_command('pmapsforledger')
1307 def PmapsForLedger(cmd_args=None):
1308 """ Find and display all pmaps currently using <ledger>.
1309 Syntax: (lldb) pmapsforledger <ledger>
1310 """
1311 if cmd_args == None or len(cmd_args) < 1:
1312 raise ArgumentError("Too few arguments to pmapsforledger.")
1313 if not kern.arch.startswith('arm'):
1314 raise NotImplementedError("pmapsforledger does not support {0}".format(kern.arch))
1315 ledger = kern.GetValueFromAddress(cmd_args[0], 'ledger_t')
1316 for pmap in IterateQueue(kern.globals.map_pmap_list, 'pmap_t', 'pmaps'):
1317 if pmap.ledger == ledger:
1318 print "pmap: {:#x}".format(pmap)