]> git.saurik.com Git - apple/xnu.git/blob - tools/lldbmacros/pmap.py
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / tools / lldbmacros / pmap.py
1 from xnu import *
2 import xnudefines
3 from kdp import *
4 from utils import *
5 import struct
6
7 def ReadPhysInt(phys_addr, bitsize = 64, cpuval = None):
8 """ Read a physical memory data based on address.
9 params:
10 phys_addr : int - Physical address to read
11 bitsize : int - defines how many bytes to read. defaults to 64 bit
12 cpuval : None (optional)
13 returns:
14 int - int value read from memory. in case of failure 0xBAD10AD is returned.
15 """
16 if "kdp" == GetConnectionProtocol():
17 return KDPReadPhysMEM(phys_addr, bitsize)
18
19 #NO KDP. Attempt to use physical memory
20 paddr_in_kva = kern.PhysToKernelVirt(long(phys_addr))
21 if paddr_in_kva :
22 if bitsize == 64 :
23 return kern.GetValueFromAddress(paddr_in_kva, 'uint64_t *').GetSBValue().Dereference().GetValueAsUnsigned()
24 if bitsize == 32 :
25 return kern.GetValueFromAddress(paddr_in_kva, 'uint32_t *').GetSBValue().Dereference().GetValueAsUnsigned()
26 if bitsize == 16 :
27 return kern.GetValueFromAddress(paddr_in_kva, 'uint16_t *').GetSBValue().Dereference().GetValueAsUnsigned()
28 if bitsize == 8 :
29 return kern.GetValueFromAddress(paddr_in_kva, 'uint8_t *').GetSBValue().Dereference().GetValueAsUnsigned()
30 return 0xBAD10AD
31
32 @lldb_command('readphys')
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>
38 nbits: 8,16,32,64
39 address: 1234 or 0x1234
40 """
41 if cmd_args == None or len(cmd_args) < 2:
42 print "Insufficient arguments.", ReadPhys.__doc__
43 return False
44 else:
45 nbits = ArgumentStringToInt(cmd_args[0])
46 phys_addr = ArgumentStringToInt(cmd_args[1])
47 print "{0: <#x}".format(ReadPhysInt(phys_addr, nbits))
48 return True
49
50 lldb_alias('readphys8', 'readphys 8 ')
51 lldb_alias('readphys16', 'readphys 16 ')
52 lldb_alias('readphys32', 'readphys 32 ')
53 lldb_alias('readphys64', 'readphys 64 ')
54
55 def KDPReadPhysMEM(address, bits):
56 """ Setup the state for READPHYSMEM64 commands for reading data via kdp
57 params:
58 address : int - address where to read the data from
59 bits : int - number of bits in the intval (8/16/32/64)
60 returns:
61 int: read value from memory.
62 0xBAD10AD: if failed to read data.
63 """
64 retval = 0xBAD10AD
65 if "kdp" != GetConnectionProtocol():
66 print "Target is not connected over kdp. Nothing to do here."
67 return retval
68
69 if "hwprobe" == KDPMode():
70 # Send the proper KDP command and payload to the bare metal debug tool via a KDP server
71 addr_for_kdp = struct.unpack("<Q", struct.pack(">Q", address))[0]
72 byte_count = struct.unpack("<I", struct.pack(">I", bits/8))[0]
73 packet = "{0:016x}{1:08x}{2:04x}".format(addr_for_kdp, byte_count, 0x0)
74
75 ret_obj = lldb.SBCommandReturnObject()
76 ci = lldb.debugger.GetCommandInterpreter()
77 ci.HandleCommand('process plugin packet send -c 25 -p {0}'.format(packet), ret_obj)
78
79 if ret_obj.Succeeded():
80 value = ret_obj.GetOutput()
81
82 if bits == 64 :
83 pack_fmt = "<Q"
84 unpack_fmt = ">Q"
85 if bits == 32 :
86 pack_fmt = "<I"
87 unpack_fmt = ">I"
88 if bits == 16 :
89 pack_fmt = "<H"
90 unpack_fmt = ">H"
91 if bits == 8 :
92 pack_fmt = "<B"
93 unpack_fmt = ">B"
94
95 retval = struct.unpack(unpack_fmt, struct.pack(pack_fmt, int(value[-((bits/4)+1):], 16)))[0]
96
97 else:
98 input_address = unsigned(addressof(kern.globals.manual_pkt.input))
99 len_address = unsigned(addressof(kern.globals.manual_pkt.len))
100 data_address = unsigned(addressof(kern.globals.manual_pkt.data))
101
102 if not WriteInt32ToMemoryAddress(0, input_address):
103 return retval
104
105 kdp_pkt_size = GetType('kdp_readphysmem64_req_t').GetByteSize()
106 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address):
107 return retval
108
109 data_addr = int(addressof(kern.globals.manual_pkt))
110 pkt = kern.GetValueFromAddress(data_addr, 'kdp_readphysmem64_req_t *')
111
112 header_value =GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_READPHYSMEM64'), length=kdp_pkt_size)
113
114 if ( WriteInt64ToMemoryAddress((header_value), int(addressof(pkt.hdr))) and
115 WriteInt64ToMemoryAddress(address, int(addressof(pkt.address))) and
116 WriteInt32ToMemoryAddress((bits/8), int(addressof(pkt.nbytes))) and
117 WriteInt16ToMemoryAddress(xnudefines.lcpu_self, int(addressof(pkt.lcpu)))
118 ):
119
120 if WriteInt32ToMemoryAddress(1, input_address):
121 # now read data from the kdp packet
122 data_address = unsigned(addressof(kern.GetValueFromAddress(int(addressof(kern.globals.manual_pkt.data)), 'kdp_readphysmem64_reply_t *').data))
123 if bits == 64 :
124 retval = kern.GetValueFromAddress(data_address, 'uint64_t *').GetSBValue().Dereference().GetValueAsUnsigned()
125 if bits == 32 :
126 retval = kern.GetValueFromAddress(data_address, 'uint32_t *').GetSBValue().Dereference().GetValueAsUnsigned()
127 if bits == 16 :
128 retval = kern.GetValueFromAddress(data_address, 'uint16_t *').GetSBValue().Dereference().GetValueAsUnsigned()
129 if bits == 8 :
130 retval = kern.GetValueFromAddress(data_address, 'uint8_t *').GetSBValue().Dereference().GetValueAsUnsigned()
131
132 return retval
133
134
135 def KDPWritePhysMEM(address, intval, bits):
136 """ Setup the state for WRITEPHYSMEM64 commands for saving data in kdp
137 params:
138 address : int - address where to save the data
139 intval : int - integer value to be stored in memory
140 bits : int - number of bits in the intval (8/16/32/64)
141 returns:
142 boolean: True if the write succeeded.
143 """
144 if "kdp" != GetConnectionProtocol():
145 print "Target is not connected over kdp. Nothing to do here."
146 return False
147
148 if "hwprobe" == KDPMode():
149 # Send the proper KDP command and payload to the bare metal debug tool via a KDP server
150 addr_for_kdp = struct.unpack("<Q", struct.pack(">Q", address))[0]
151 byte_count = struct.unpack("<I", struct.pack(">I", bits/8))[0]
152
153 if bits == 64 :
154 pack_fmt = ">Q"
155 unpack_fmt = "<Q"
156 if bits == 32 :
157 pack_fmt = ">I"
158 unpack_fmt = "<I"
159 if bits == 16 :
160 pack_fmt = ">H"
161 unpack_fmt = "<H"
162 if bits == 8 :
163 pack_fmt = ">B"
164 unpack_fmt = "<B"
165
166 data_val = struct.unpack(unpack_fmt, struct.pack(pack_fmt, intval))[0]
167
168 packet = "{0:016x}{1:08x}{2:04x}{3:016x}".format(addr_for_kdp, byte_count, 0x0, data_val)
169
170 ret_obj = lldb.SBCommandReturnObject()
171 ci = lldb.debugger.GetCommandInterpreter()
172 ci.HandleCommand('process plugin packet send -c 26 -p {0}'.format(packet), ret_obj)
173
174 if ret_obj.Succeeded():
175 return True
176 else:
177 return False
178
179 else:
180 input_address = unsigned(addressof(kern.globals.manual_pkt.input))
181 len_address = unsigned(addressof(kern.globals.manual_pkt.len))
182 data_address = unsigned(addressof(kern.globals.manual_pkt.data))
183 if not WriteInt32ToMemoryAddress(0, input_address):
184 return False
185
186 kdp_pkt_size = GetType('kdp_writephysmem64_req_t').GetByteSize() + (bits / 8)
187 if not WriteInt32ToMemoryAddress(kdp_pkt_size, len_address):
188 return False
189
190 data_addr = int(addressof(kern.globals.manual_pkt))
191 pkt = kern.GetValueFromAddress(data_addr, 'kdp_writephysmem64_req_t *')
192
193 header_value =GetKDPPacketHeaderInt(request=GetEnumValue('kdp_req_t::KDP_WRITEPHYSMEM64'), length=kdp_pkt_size)
194
195 if ( WriteInt64ToMemoryAddress((header_value), int(addressof(pkt.hdr))) and
196 WriteInt64ToMemoryAddress(address, int(addressof(pkt.address))) and
197 WriteInt32ToMemoryAddress((bits/8), int(addressof(pkt.nbytes))) and
198 WriteInt16ToMemoryAddress(xnudefines.lcpu_self, int(addressof(pkt.lcpu)))
199 ):
200
201 if bits == 8:
202 if not WriteInt8ToMemoryAddress(intval, int(addressof(pkt.data))):
203 return False
204 if bits == 16:
205 if not WriteInt16ToMemoryAddress(intval, int(addressof(pkt.data))):
206 return False
207 if bits == 32:
208 if not WriteInt32ToMemoryAddress(intval, int(addressof(pkt.data))):
209 return False
210 if bits == 64:
211 if not WriteInt64ToMemoryAddress(intval, int(addressof(pkt.data))):
212 return False
213 if WriteInt32ToMemoryAddress(1, input_address):
214 return True
215 return False
216
217
218 def WritePhysInt(phys_addr, int_val, bitsize = 64):
219 """ Write and integer value in a physical memory data based on address.
220 params:
221 phys_addr : int - Physical address to read
222 int_val : int - int value to write in memory
223 bitsize : int - defines how many bytes to read. defaults to 64 bit
224 returns:
225 bool - True if write was successful.
226 """
227 if "kdp" == GetConnectionProtocol():
228 if not KDPWritePhysMEM(phys_addr, int_val, bitsize):
229 print "Failed to write via KDP."
230 return False
231 return True
232 #We are not connected via KDP. So do manual math and savings.
233 print "Failed: Write to physical memory is not supported for %s connection." % GetConnectionProtocol()
234 return False
235
236 @lldb_command('writephys')
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>
242 nbits: 8,16,32,64
243 address: 1234 or 0x1234
244 value: int value to be written
245 ex. (lldb)writephys 16 0x12345abcd 0x25
246 """
247 if cmd_args == None or len(cmd_args) < 3:
248 print "Invalid arguments.", WritePhys.__doc__
249 else:
250 nbits = ArgumentStringToInt(cmd_args[0])
251 phys_addr = ArgumentStringToInt(cmd_args[1])
252 int_value = ArgumentStringToInt(cmd_args[2])
253 print WritePhysInt(phys_addr, int_value, nbits)
254
255
256 lldb_alias('writephys8', 'writephys 8 ')
257 lldb_alias('writephys16', 'writephys 16 ')
258 lldb_alias('writephys32', 'writephys 32 ')
259 lldb_alias('writephys64', 'writephys 64 ')
260
261
262 def _PT_Step(paddr, index, verbose_level = vSCRIPT):
263 """
264 Step to lower-level page table and print attributes
265 paddr: current page table entry physical address
266 index: current page table entry index (0..511)
267 verbose_level: vHUMAN: print nothing
268 vSCRIPT: print basic information
269 vDETAIL: print basic information and hex table dump
270 returns: (pt_paddr, pt_valid, pt_large)
271 pt_paddr: next level page table entry physical address
272 or null if invalid
273 pt_valid: 1 if $kgm_pt_paddr is valid, 0 if the walk
274 should be aborted
275 pt_large: 1 if kgm_pt_paddr is a page frame address
276 of a large page and not another page table entry
277 """
278 entry_addr = paddr + (8 * index)
279 entry = ReadPhysInt(entry_addr, 64, xnudefines.lcpu_self )
280 out_string = ''
281 if verbose_level >= vDETAIL:
282 for pte_loop in range(0, 512):
283 paddr_tmp = paddr + (8 * pte_loop)
284 out_string += "{0: <#020x}:\t {1: <#020x}\n".format(paddr_tmp, ReadPhysInt(paddr_tmp, 64, xnudefines.lcpu_self))
285 paddr_mask = ~((0xfff<<52) | 0xfff)
286 paddr_large_mask = ~((0xfff<<52) | 0x1fffff)
287 pt_valid = False
288 pt_large = False
289 pt_paddr = 0
290 if verbose_level < vSCRIPT:
291 if entry & 0x1 :
292 pt_valid = True
293 pt_large = False
294 pt_paddr = entry & paddr_mask
295 if entry & (0x1 <<7):
296 pt_large = True
297 pt_paddr = entry & paddr_large_mask
298 else:
299 out_string+= "{0: <#020x}:\n\t{1:#020x}\n\t".format(entry_addr, entry)
300 if entry & 0x1:
301 out_string += " valid"
302 pt_paddr = entry & paddr_mask
303 pt_valid = True
304 else:
305 out_string += " invalid"
306 pt_paddr = 0
307 pt_valid = False
308 if entry & (0x1 << 62):
309 out_string += " compressed"
310 #Stop decoding other bits
311 entry = 0
312 if entry & (0x1 << 1):
313 out_string += " writable"
314 else:
315 out_string += " read-only"
316
317 if entry & (0x1 << 2):
318 out_string += " user"
319 else:
320 out_string += " supervisor"
321
322 if entry & (0x1 << 3):
323 out_string += " PWT"
324
325 if entry & (0x1 << 4):
326 out_string += " PCD"
327
328 if entry & (0x1 << 5):
329 out_string += " accessed"
330
331 if entry & (0x1 << 6):
332 out_string += " dirty"
333
334 if entry & (0x1 << 7):
335 out_string += " large"
336 pt_large = True
337 else:
338 pt_large = False
339
340 if entry & (0x1 << 8):
341 out_string += " global"
342
343 if entry & (0x3 << 9):
344 out_string += " avail:{0:x}".format((entry >> 9) & 0x3)
345
346 if entry & (0x1 << 63):
347 out_string += " noexec"
348 print out_string
349 return (pt_paddr, pt_valid, pt_large)
350
351 def _PT_StepEPT(paddr, index, verbose_level = vSCRIPT):
352 """
353 Step to lower-level page table and print attributes for EPT pmap
354 paddr: current page table entry physical address
355 index: current page table entry index (0..511)
356 verbose_level: vHUMAN: print nothing
357 vSCRIPT: print basic information
358 vDETAIL: print basic information and hex table dump
359 returns: (pt_paddr, pt_valid, pt_large)
360 pt_paddr: next level page table entry physical address
361 or null if invalid
362 pt_valid: 1 if $kgm_pt_paddr is valid, 0 if the walk
363 should be aborted
364 pt_large: 1 if kgm_pt_paddr is a page frame address
365 of a large page and not another page table entry
366 """
367 entry_addr = paddr + (8 * index)
368 entry = ReadPhysInt(entry_addr, 64, xnudefines.lcpu_self )
369 out_string = ''
370 if verbose_level >= vDETAIL:
371 for pte_loop in range(0, 512):
372 paddr_tmp = paddr + (8 * pte_loop)
373 out_string += "{0: <#020x}:\t {1: <#020x}\n".format(paddr_tmp, ReadPhysInt(paddr_tmp, 64, xnudefines.lcpu_self))
374 paddr_mask = ~((0xfff<<52) | 0xfff)
375 paddr_large_mask = ~((0xfff<<52) | 0x1fffff)
376 pt_valid = False
377 pt_large = False
378 pt_paddr = 0
379 if verbose_level < vSCRIPT:
380 if entry & 0x7 :
381 pt_valid = True
382 pt_large = False
383 pt_paddr = entry & paddr_mask
384 if entry & (0x1 <<7):
385 pt_large = True
386 pt_paddr = entry & paddr_large_mask
387 else:
388 out_string+= "{0: <#020x}:\n\t{1:#020x}\n\t".format(entry_addr, entry)
389 if entry & 0x7:
390 out_string += "valid"
391 pt_paddr = entry & paddr_mask
392 pt_valid = True
393 else:
394 out_string += "invalid"
395 pt_paddr = 0
396 pt_valid = False
397 if entry & (0x1 << 62):
398 out_string += " compressed"
399 #Stop decoding other bits
400 entry = 0
401 if entry & 0x1:
402 out_string += " readable"
403 else:
404 out_string += " no read"
405 if entry & (0x1 << 1):
406 out_string += " writable"
407 else:
408 out_string += " no write"
409
410 if entry & (0x1 << 2):
411 out_string += " executable"
412 else:
413 out_string += " no exec"
414
415 ctype = entry & 0x38
416 if ctype == 0x30:
417 out_string += " cache-WB"
418 elif ctype == 0x28:
419 out_string += " cache-WP"
420 elif ctype == 0x20:
421 out_string += " cache-WT"
422 elif ctype == 0x8:
423 out_string += " cache-WC"
424 else:
425 out_string += " cache-NC"
426
427 if (entry & 0x40) == 0x40:
428 out_string += " Ignore-PTA"
429
430 if (entry & 0x100) == 0x100:
431 out_string += " accessed"
432
433 if (entry & 0x200) == 0x200:
434 out_string += " dirty"
435
436 if entry & (0x1 << 7):
437 out_string += " large"
438 pt_large = True
439 else:
440 pt_large = False
441 print out_string
442 return (pt_paddr, pt_valid, pt_large)
443
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
448 """
449 pt_paddr = unsigned(pmap_addr_val)
450 pt_valid = (unsigned(pmap_addr_val) != 0)
451 pt_large = 0
452 pframe_offset = 0
453 if pt_valid:
454 # Lookup bits 47:39 of linear address in PML4T
455 pt_index = (vaddr >> 39) & 0x1ff
456 pframe_offset = vaddr & 0x7fffffffff
457 if verbose_level > vHUMAN :
458 print "pml4 (index {0:d}):".format(pt_index)
459 if not(ept_pmap):
460 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
461 else:
462 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level)
463 if pt_valid:
464 # Lookup bits 38:30 of the linear address in PDPT
465 pt_index = (vaddr >> 30) & 0x1ff
466 pframe_offset = vaddr & 0x3fffffff
467 if verbose_level > vHUMAN:
468 print "pdpt (index {0:d}):".format(pt_index)
469 if not(ept_pmap):
470 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
471 else:
472 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level)
473 if pt_valid and not pt_large:
474 #Lookup bits 29:21 of the linear address in PDPT
475 pt_index = (vaddr >> 21) & 0x1ff
476 pframe_offset = vaddr & 0x1fffff
477 if verbose_level > vHUMAN:
478 print "pdt (index {0:d}):".format(pt_index)
479 if not(ept_pmap):
480 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
481 else:
482 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level)
483 if pt_valid and not pt_large:
484 #Lookup bits 20:21 of linear address in PT
485 pt_index = (vaddr >> 12) & 0x1ff
486 pframe_offset = vaddr & 0xfff
487 if verbose_level > vHUMAN:
488 print "pt (index {0:d}):".format(pt_index)
489 if not(ept_pmap):
490 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
491 else:
492 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level)
493 paddr = 0
494 paddr_isvalid = False
495 if pt_valid:
496 paddr = pt_paddr + pframe_offset
497 paddr_isvalid = True
498
499 if verbose_level > vHUMAN:
500 if paddr_isvalid:
501 pvalue = ReadPhysInt(paddr, 32, xnudefines.lcpu_self)
502 print "phys {0: <#020x}: {1: <#020x}".format(paddr, pvalue)
503 else:
504 print "no translation"
505
506 return paddr
507
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
514 """
515 out_string = ""
516 if level == 1 and (tte & 0x3) == 0x2:
517 if verbose_level < vSCRIPT:
518 return
519
520 #bit [1:0] evaluated in PmapWalkARM
521 # B bit 2
522 b_bit = (tte & 0x4) >> 2
523 # C bit 3
524 c_bit = (tte & 0x8) >> 3
525 #XN bit 4
526 if (tte & 0x10) :
527 out_string += "no-execute"
528 else:
529 out_string += "execute"
530 #Domain bit [8:5] if not supersection
531 if (tte & 0x40000) == 0x0:
532 out_string += " domain ({:d})".format(((tte & 0x1e0) >> 5) )
533 #IMP bit 9
534 out_string += " imp({:d})".format( ((tte & 0x200) >> 9) )
535 # AP bit 15 and [11:10] merged to a single 3 bit value
536 access = ( (tte & 0xc00) >> 10 ) | ((tte & 0x8000) >> 13)
537 out_string += xnudefines.arm_level2_access_strings[access]
538
539 #TEX bit [14:12]
540 tex_bits = ((tte & 0x7000) >> 12)
541 #Print TEX, C , B all together
542 out_string += " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format(
543 1 if (tex_bits & 0x4) else 0,
544 1 if (tex_bits & 0x2) else 0,
545 1 if (tex_bits & 0x1) else 0,
546 c_bit,
547 b_bit
548 )
549 # S bit 16
550 if tte & 0x10000:
551 out_string += " shareable"
552 else:
553 out_string += " not-shareable"
554 # nG bit 17
555 if tte & 0x20000 :
556 out_string += " not-global"
557 else:
558 out_string += " global"
559 # Supersection bit 18
560 if tte & 0x40000:
561 out_string += " supersection"
562 else:
563 out_string += " section"
564 #NS bit 19
565 if tte & 0x80000 :
566 out_string += " no-secure"
567 else:
568 out_string += " secure"
569
570 elif level == 1 and (tte & 0x3) == 0x1:
571
572 if verbose_level >= vSCRIPT:
573 # bit [1:0] evaluated in PmapWalkARM
574 # NS bit 3
575 if tte & 0x8:
576 out_string += ' no-secure'
577 else:
578 out_string += ' secure'
579 #Domain bit [8:5]
580 out_string += " domain({:d})".format(((tte & 0x1e0) >> 5))
581 # IMP bit 9
582 out_string += " imp({:d})".format( ((tte & 0x200) >> 9))
583 out_string += "\n"
584
585 elif level == 2:
586 pte = tte
587 if verbose_level >= vSCRIPT:
588 if (pte & 0x3) == 0x0:
589 out_string += " invalid"
590 else:
591 if (pte & 0x3) == 0x1:
592 out_string += " large"
593 # XN bit 15
594 if pte & 0x8000 == 0x8000:
595 out_string+= " no-execute"
596 else:
597 out_string += " execute"
598 else:
599 out_string += " small"
600 # XN bit 0
601 if (pte & 0x1) == 0x01:
602 out_string += " no-execute"
603 else:
604 out_string += " execute"
605 # B bit 2
606 b_bit = (pte & 0x4) >> 2
607 c_bit = (pte & 0x8) >> 3
608 # AP bit 9 and [5:4], merged to a single 3-bit value
609 access = (pte & 0x30) >> 4 | (pte & 0x200) >> 7
610 out_string += xnudefines.arm_level2_access_strings[access]
611
612 #TEX bit [14:12] for large, [8:6] for small
613 tex_bits = ((pte & 0x1c0) >> 6)
614 if (pte & 0x3) == 0x1:
615 tex_bits = ((pte & 0x7000) >> 12)
616
617 # Print TEX, C , B alltogether
618 out_string += " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format(
619 1 if (tex_bits & 0x4) else 0,
620 1 if (tex_bits & 0x2) else 0,
621 1 if (tex_bits & 0x1) else 0,
622 c_bit,
623 b_bit
624 )
625 # S bit 10
626 if pte & 0x400 :
627 out_string += " shareable"
628 else:
629 out_string += " not-shareable"
630
631 # nG bit 11
632 if pte & 0x800:
633 out_string += " not-global"
634 else:
635 out_string += " global"
636
637 print out_string
638
639
640 def _PmapWalkARMLevel1Section(tte, vaddr, verbose_level = vSCRIPT):
641 paddr = 0
642 #Supersection or just section?
643 if (tte & 0x40000) == 0x40000:
644 paddr = ( (tte & 0xFF000000) | (vaddr & 0x00FFFFFF) )
645 else:
646 paddr = ( (tte & 0xFFF00000) | (vaddr & 0x000FFFFF) )
647
648 if verbose_level >= vSCRIPT:
649 print "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte), tte),
650
651 PmapDecodeTTEARM(tte, 1, verbose_level)
652
653 return paddr
654
655
656
657 def _PmapWalkARMLevel2(tte, vaddr, verbose_level = vSCRIPT):
658 """ Pmap walk the level 2 tte.
659 params:
660 tte - value object
661 vaddr - int
662 returns: str - description of the tte + additional informaiton based on verbose_level
663 """
664 pte_base = kern.PhysToKernelVirt(tte & 0xFFFFFC00)
665 pte_index = (vaddr >> 12) & 0xFF
666 pte_base_val = kern.GetValueFromAddress(pte_base, 'pt_entry_t *')
667 pte = pte_base_val[pte_index]
668
669 paddr = 0
670 if pte & 0x2:
671 paddr = (unsigned(pte) & 0xFFFFF000) | (vaddr & 0xFFF)
672
673 if verbose_level >= vSCRIPT:
674 print "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte), tte),
675
676 PmapDecodeTTEARM(tte, 1, verbose_level)
677 if verbose_level >= vSCRIPT:
678 print "second-level table (index {:d}):".format(pte_index)
679 if verbose_level >= vDETAIL:
680 for i in range(256):
681 tmp = pte_base_val[i]
682 print "{0: <#020x}:\t{1: <#020x}".format(addressof(tmp), unsigned(tmp))
683
684 if verbose_level >= vSCRIPT:
685 print " {0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(pte), unsigned(pte)),
686
687 PmapDecodeTTEARM(pte, 2, verbose_level)
688
689 return paddr
690 #end of level 2 walking of arm
691
692
693 def PmapWalkARM(pmap, vaddr, verbose_level = vHUMAN):
694 """ Pmap walking for ARM kernel.
695 params:
696 pmapval: core.value - representing pmap_t in kernel
697 vaddr: int - integer representing virtual address to walk
698 """
699 paddr = 0
700 # shift by TTESHIFT (20) to get tte index
701 # Assume all L1 indexing starts at VA 0...for our purposes it does,
702 # as that's where all user pmaps start, and the kernel pmap contains
703 # 4 L1 pages (the lower 2 of which are unused after bootstrap)
704 tte_index = vaddr >> 20
705 tte = pmap.tte[tte_index]
706 if verbose_level >= vSCRIPT:
707 print "First-level table (index {:d}):".format(tte_index)
708 if verbose_level >= vDETAIL:
709 for i in range(0, pmap.tte_index_max):
710 ptr = unsigned(addressof(pmap.tte[i]))
711 val = unsigned(pmap.tte[i])
712 print "{0: <#020x}:\t {1: <#020x}".format(ptr, val)
713 if (tte & 0x3) == 0x1:
714 paddr = _PmapWalkARMLevel2(tte, vaddr, verbose_level)
715 elif (tte & 0x3) == 0x2 :
716 paddr = _PmapWalkARMLevel1Section(tte, vaddr, verbose_level)
717 else:
718 paddr = 0
719 if verbose_level >= vSCRIPT:
720 print "Invalid First-Level Translation Table Entry: {0: #020x}".format(tte)
721
722 if verbose_level >= vHUMAN:
723 if paddr:
724 print "Translation of {:#x} is {:#x}.".format(vaddr, paddr)
725 else:
726 print "(no translation)"
727
728 return paddr
729
730 def PmapWalkX86_64(pmapval, vaddr, verbose_level = vSCRIPT):
731 """
732 params: pmapval - core.value representing pmap_t in kernel
733 vaddr: int - int representing virtual address to walk
734 """
735 if pmapval.pm_cr3 != 0:
736 if verbose_level > vHUMAN:
737 print "Using normal Intel PMAP from pm_cr3\n"
738 return _PmapL4Walk(pmapval.pm_cr3, vaddr, 0, config['verbosity'])
739 else:
740 if verbose_level > vHUMAN:
741 print "Using EPT pmap from pm_eptp\n"
742 return _PmapL4Walk(pmapval.pm_eptp, vaddr, 1, config['verbosity'])
743
744 def assert_64bit(val):
745 assert(val < 2**64)
746
747 ARM64_TTE_SIZE = 8
748 ARM64_TTE_SHIFT = 3
749 ARM64_VMADDR_BITS = 48
750
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
755
756 def PmapBlockBaseMaskARM64(page_size, level):
757 assert level >= 0 and level <= 3
758 return ((1 << ARM64_VMADDR_BITS) - 1) & ~PmapBlockOffsetMaskARM64(page_size, level)
759
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.
765 """
766 assert(type(level) == int)
767 assert_64bit(tte)
768
769 if tte & 0x1 == 0x0:
770 print("Invalid.")
771 return
772
773 if (tte & 0x2 == 0x2) and (level != 0x3):
774 print "Type = Table pointer."
775 print "Table addr = {:#x}.".format(tte & 0xfffffffff000)
776
777 if not stage2:
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)
782 else:
783 print "Type = Block."
784
785 if stage2:
786 print "S2 MemAttr = {:#x}.".format((tte >> 2) & 0xf)
787 else:
788 print "AttrIdx = {:#x}.".format((tte >> 2) & 0x7)
789 print "NS = {:#x}.".format((tte >> 5) & 0x1)
790
791 if stage2:
792 print "S2AP = {:#x}.".format((tte >> 6) & 0x3)
793 else:
794 print "AP = {:#x}.".format((tte >> 6) & 0x3)
795
796 print "SH = {:#x}.".format((tte >> 8) & 0x3)
797 print "AF = {:#x}.".format((tte >> 10) & 0x1)
798
799 if not stage2:
800 print "nG = {:#x}.".format((tte >> 11) & 0x1)
801
802 print "HINT = {:#x}.".format((tte >> 52) & 0x1)
803
804 if stage2:
805 print "S2XN = {:#x}.".format((tte >> 53) & 0x3)
806 else:
807 print "PXN = {:#x}.".format((tte >> 53) & 0x1)
808 print "XN = {:#x}.".format((tte >> 54) & 0x1)
809
810 print "SW Use = {:#x}.".format((tte >> 55) & 0xf)
811
812 return
813
814 def PmapTTnIndexARM64(vaddr, pmap_pt_attr):
815 pta_max_level = unsigned(pmap_pt_attr.pta_max_level)
816
817 tt_index = []
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))
821
822 return tt_index
823
824 def PmapWalkARM64(pmap_pt_attr, root_tte, vaddr, verbose_level = vHUMAN):
825 assert(type(vaddr) in (long, int))
826 assert_64bit(vaddr)
827 assert_64bit(root_tte)
828
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)
835
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)
839
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]))
844
845 # Walk the page tables
846 paddr = -1
847 max_level = unsigned(pmap_pt_attr.pta_max_level)
848
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)
854
855 if tte & 0x1 == 0x0:
856 if verbose_level >= vHUMAN:
857 print "L{} entry invalid: {:#x}\n".format(level, tte)
858 break
859
860 # Handle leaf entry
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)
866
867 if level != max_level:
868 print "phys: {:#x}".format(paddr)
869
870 break
871 else:
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)
875
876 next_virt = kern.PhysToKernelVirt(next_phys)
877 assert(type(next_virt) == long)
878
879 if verbose_level >= vDETAIL:
880 print "L{} physical address: {:#x}. L{} virtual address: {:#x}".format(level + 1, next_phys, level + 1, next_virt)
881
882 ttep = kern.GetValueFromAddress(next_virt, "tt_entry_t*")
883 tte = long(unsigned(dereference(ttep)))
884 assert(type(tte) == long)
885
886 # We've parsed one level, so go to the next level
887 assert(level <= 3)
888 level = level + 1
889
890 if verbose_level >= vHUMAN:
891 if paddr:
892 print "Translation of {:#x} is {:#x}.".format(vaddr, paddr)
893 else:
894 print "(no translation)"
895
896 return paddr
897
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)
907 else:
908 raise NotImplementedError("PmapWalk does not support {0}".format(kern.arch))
909
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
915 """
916 if cmd_args == None or len(cmd_args) < 2:
917 raise ArgumentError("Too few arguments to pmap_walk.")
918
919 pmap = kern.GetValueAsType(cmd_args[0], 'pmap_t')
920 addr = ArgumentStringToInt(cmd_args[1])
921 PmapWalk(pmap, addr, config['verbosity'])
922 return
923
924 def GetMemoryAttributesFromUser(requested_type):
925 pmap_attr_dict = {
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,
929 }
930
931 requested_type = requested_type.lower()
932 if requested_type not in pmap_attr_dict:
933 return None
934
935 return pmap_attr_dict[requested_type]
936
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
942 """
943 if cmd_args == None or len(cmd_args) < 2:
944 raise ArgumentError("Too few arguments to ttep_walk.")
945
946 if not kern.arch.startswith('arm64'):
947 raise NotImplementedError("ttep_walk does not support {0}".format(kern.arch))
948
949 tte = kern.GetValueFromAddress(kern.PhysToKernelVirt(ArgumentStringToInt(cmd_args[0])), 'unsigned long *')
950 addr = ArgumentStringToInt(cmd_args[1])
951
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.")
955
956 return PmapWalkARM64(pmap_pt_attr, tte, addr, config['verbosity'])
957
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]
962 """
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)
972 else:
973 raise NotImplementedError("decode_tte does not support {0}".format(kern.arch))
974
975
976 PVH_HIGH_FLAGS_ARM64 = (1 << 62) | (1 << 61) | (1 << 60) | (1 << 59)
977 PVH_HIGH_FLAGS_ARM32 = (1 << 31)
978
979 def PVWalkARM(pa):
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
982 """
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])
990 pvh_type = pvh & 0x3
991 print "PVH raw value: ({:#x})".format(pvh)
992 if kern.arch.startswith('arm64'):
993 iommu_flag = 0x4
994 iommu_table_flag = 1 << 63
995 pvh = pvh | PVH_HIGH_FLAGS_ARM64
996 else:
997 iommu_flag = 0
998 iommu_table_flag = 0
999 pvh = pvh | PVH_HIGH_FLAGS_ARM32
1000 if pvh_type == 0:
1001 print "PVH type: NULL"
1002 return
1003 elif pvh_type == 3:
1004 print "PVH type: page-table descriptor ({:#x})".format(pvh & ~0x3)
1005 return
1006 elif pvh_type == 2:
1007 ptep = pvh & ~0x3
1008 pte_str = ''
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'
1014 else:
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 *')))
1018 elif pvh_type == 1:
1019 pvep = pvh & ~0x3
1020 print "PVH type: PTE list"
1021 while pvep != 0:
1022 pve = kern.GetValueFromAddress(pvep, "pv_entry_t *")
1023 if unsigned(pve.pve_next) & 0x1:
1024 pve_str = ' (alt acct) '
1025 else:
1026 pve_str = ''
1027 current_pvep = pvep
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'
1034 else:
1035 pve_str = ' (IOMMU state), descriptor'
1036 ptep = ptep | iommu_table_flag
1037 try:
1038 print "PVE {:#x}, PTE {:#x}{:s}: {:#x}".format(current_pvep, ptep, pve_str, dereference(kern.GetValueFromAddress(ptep, 'pt_entry_t *')))
1039 except:
1040 print "PVE {:#x}, PTE {:#x}{:s}: <unavailable>".format(current_pvep, ptep, pve_str)
1041
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>
1046 """
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'))
1052
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>
1058 """
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))
1065
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>
1071 """
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')))))
1075
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))
1083
1084
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
1090 else:
1091 pvh = pvh | PVH_HIGH_FLAGS_ARM32
1092 pvh_type = pvh & 0x3
1093 if pvh_type != 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 *')
1096 return ptd
1097
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.
1101 """
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
1110 else:
1111 pte_pgoff = pte_pgoff / 4
1112 nttes = page_size / 4
1113 if ptd.ptd_info[pt_index].refcnt == 0x4000:
1114 level = 2
1115 granule = nttes * page_size
1116 else:
1117 level = 3
1118 granule = 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)
1127
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]
1132 """
1133 if cmd_args == None or len(cmd_args) < 1:
1134 raise ArgumentError("Too few arguments to showpte.")
1135
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.")
1142
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)
1145 else:
1146 raise NotImplementedError("showpte does not support {0}".format(kern.arch))
1147
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
1155 """
1156 for i in range(nttes):
1157 try:
1158 tte = tt[i]
1159 va_size = None
1160 if level == 1:
1161 if tte & 0x3 == 0x1:
1162 type = 'table'
1163 granule = 1024
1164 va_size = kern.globals.page_size * 256
1165 paddr = tte & 0xFFFFFC00
1166 elif tte & 0x3 == 0x2:
1167 type = 'block'
1168 if (tte & 0x40000) == 0x40000:
1169 granule = 1 << 24
1170 paddr = tte & 0xFF000000
1171 else:
1172 granule = 1 << 20
1173 paddr = tte & 0xFFF00000
1174 else:
1175 continue
1176 elif (tte & 0x3) == 0x1:
1177 type = 'entry'
1178 granule = 1 << 16
1179 paddr = tte & 0xFFFF0000
1180 elif (tte & 0x3) != 0:
1181 type = 'entry'
1182 granule = 1 << 12
1183 paddr = tte & 0xFFFFF000
1184 else:
1185 continue
1186 if va_size is None:
1187 va_size = granule
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])))
1195
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
1203 """
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)
1210
1211 for i in range(nttes):
1212 try:
1213 tte = tt[i]
1214 if tte & 0x1 == 0x0:
1215 continue
1216
1217 tt_next = None
1218 paddr = unsigned(tte) & unsigned(page_base_mask)
1219
1220 # Handle leaf entry
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
1224 else:
1225 # Handle page table entry
1226 type = 'table'
1227 granule = page_size
1228 tt_next = kern.GetValueFromAddress(kern.PhysToKernelVirt(paddr), 'tt_entry_t *')
1229
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)
1234
1235 except Exception as exc:
1236 print "Unable to access tte {:#x}".format(unsigned(addressof(tt[i])))
1237
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.
1242 """
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
1254
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)
1260
1261 if targetPmap is not None:
1262 ScanPmap(kern.GetValueFromAddress(targetPmap, 'pmap_t'), action)
1263 else:
1264 for pmap in IterateQueue(kern.globals.map_pmap_list, 'pmap_t', 'pmaps'):
1265 ScanPmap(pmap, action)
1266
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!
1274 """
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')
1280 targetPmap = None
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)
1286 return True
1287 ScanPageTables(printMatchedMapping, targetPmap)
1288
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!
1294 """
1295 if not kern.arch.startswith('arm'):
1296 raise NotImplementedError("showptusage does not support {0}".format(kern.arch))
1297 targetPmap = None
1298 if len(cmd_args) > 0:
1299 targetPmap = cmd_args[0]
1300 lastPmap = [None]
1301 numTables = [0]
1302 numUnnested = [0]
1303 numPmaps = [0]
1304 def printValidTTE(pmap, level, type, tte, paddr, va, granule):
1305 unnested = ""
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]):
1309 lastPmap[0] = pmap
1310 numPmaps[0] = numPmaps[0] + 1
1311 print ("pmap {:#x}:".format(pmap))
1312 if type == 'root':
1313 return True
1314 if (level == 2) and (va >= nested_region_addr) and (va < nested_region_end):
1315 ptd = GetPtDesc(paddr)
1316 if ptd.pmap != pmap:
1317 return False
1318 else:
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
1323 if level == 2:
1324 return False
1325 else:
1326 return True
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]))
1329
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.
1334 type: unused
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.
1337 granule: unused
1338 """
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
1346 max_level = 3
1347 pvh_set_bits = PVH_HIGH_FLAGS_ARM64
1348 elif kern.arch == 'arm':
1349 page_base_mask = 0xFFFFF000
1350 paddr = paddr & page_base_mask
1351 max_level = 2
1352 pvh_set_bits = PVH_HIGH_FLAGS_ARM32
1353 if level < max_level or paddr < vm_first_phys or paddr >= vm_last_phys:
1354 return True
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)
1360 else:
1361 pmap_str = ''
1362 if tte is not None:
1363 tte_str = "pte {:#x} ({:#x}): ".format(unsigned(tte), paddr)
1364 else:
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)
1368 elif pvh_type == 2:
1369 ptep = pvh & ~0x3
1370 if tte is not None and ptep != unsigned(tte):
1371 print "{:s}{:s}PVH mismatch ({:#x})".format(pmap_str, tte_str, ptep)
1372 try:
1373 pte = long(unsigned(dereference(kern.GetValueFromAddress(ptep, 'pt_entry_t *')))) & page_base_mask
1374 if (pte != paddr):
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)
1378 elif pvh_type == 1:
1379 pvep = pvh & ~0x3
1380 tte_match = False
1381 while pvep != 0:
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):
1386 tte_match = True
1387 try:
1388 pte = long(unsigned(dereference(kern.GetValueFromAddress(ptep, 'pt_entry_t *')))) & page_base_mask
1389 if (pte != paddr):
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)
1395 return True
1396
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
1402 """
1403 if cmd_args == None or len(cmd_args) < 1:
1404 raise ArgumentError("Too few arguments to pv_check.")
1405 if kern.arch == 'arm':
1406 level = 2
1407 elif kern.arch.startswith('arm64'):
1408 level = 3
1409 else:
1410 raise NotImplementedError("pv_check does not support {0}".format(kern.arch))
1411 if "-P" in cmd_options:
1412 pte = None
1413 pa = long(unsigned(kern.GetValueFromAddress(cmd_args[0], "unsigned long")))
1414 else:
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)
1418
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.
1428 """
1429 if not kern.arch.startswith('arm'):
1430 raise NotImplementedError("check_pmaps does not support {0}".format(kern.arch))
1431 targetPmap = None
1432 if len(cmd_args) > 0:
1433 targetPmap = cmd_args[0]
1434 ScanPageTables(checkPVList, targetPmap)
1435
1436 @lldb_command('pmapsforledger')
1437 def PmapsForLedger(cmd_args=None):
1438 """ Find and display all pmaps currently using <ledger>.
1439 Syntax: (lldb) pmapsforledger <ledger>
1440 """
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)
1449