]> git.saurik.com Git - apple/xnu.git/blob - tools/lldbmacros/pmap.py
xnu-3248.60.10.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
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()
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 is_cpu64_bit = int(kern.globals.cpu_64bit)
385 pt_paddr = unsigned(pmap_addr_val)
386 pt_valid = (unsigned(pmap_addr_val) != 0)
387 pt_large = 0
388 pframe_offset = 0
389 if pt_valid and is_cpu64_bit:
390 # Lookup bits 47:39 of linear address in PML4T
391 pt_index = (vaddr >> 39) & 0x1ff
392 pframe_offset = vaddr & 0x7fffffffff
393 if verbose_level > vHUMAN :
394 print "pml4 (index {0:d}):".format(pt_index)
395 if not(ept_pmap):
396 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
397 else:
398 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level)
399 if pt_valid:
400 # Lookup bits 38:30 of the linear address in PDPT
401 pt_index = (vaddr >> 30) & 0x1ff
402 pframe_offset = vaddr & 0x3fffffff
403 if verbose_level > vHUMAN:
404 print "pdpt (index {0:d}):".format(pt_index)
405 if not(ept_pmap):
406 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
407 else:
408 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level)
409 if pt_valid and not pt_large:
410 #Lookup bits 29:21 of the linear address in PDPT
411 pt_index = (vaddr >> 21) & 0x1ff
412 pframe_offset = vaddr & 0x1fffff
413 if verbose_level > vHUMAN:
414 print "pdt (index {0:d}):".format(pt_index)
415 if not(ept_pmap):
416 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
417 else:
418 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level)
419 if pt_valid and not pt_large:
420 #Lookup bits 20:21 of linear address in PT
421 pt_index = (vaddr >> 12) & 0x1ff
422 pframe_offset = vaddr & 0xfff
423 if verbose_level > vHUMAN:
424 print "pt (index {0:d}):".format(pt_index)
425 if not(ept_pmap):
426 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
427 else:
428 (pt_paddr, pt_valid, pt_large) = _PT_StepEPT(pt_paddr, pt_index, verbose_level)
429 paddr = 0
430 paddr_isvalid = False
431 if pt_valid:
432 paddr = pt_paddr + pframe_offset
433 paddr_isvalid = True
434
435 if verbose_level > vHUMAN:
436 if paddr_isvalid:
437 pvalue = ReadPhysInt(paddr, 32, xnudefines.lcpu_self)
438 print "phys {0: <#020x}: {1: <#020x}".format(paddr, pvalue)
439 else:
440 print "no translation"
441
442 return paddr
443
444 def _PmapWalkARMLevel1Section(tte, vaddr, verbose_level = vSCRIPT):
445 paddr = 0
446 out_string = ""
447 #Supersection or just section?
448 if (tte & 0x40000) == 0x40000:
449 paddr = ( (tte & 0xFF000000) | (vaddr & 0x00FFFFFF) )
450 else:
451 paddr = ( (tte & 0xFFF00000) | (vaddr & 0x000FFFFF) )
452
453 if verbose_level >= vSCRIPT:
454 out_string += "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte), tte)
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 print out_string
506 return paddr
507
508
509
510 def _PmapWalkARMLevel2(tte, vaddr, verbose_level = vSCRIPT):
511 """ Pmap walk the level 2 tte.
512 params:
513 tte - value object
514 vaddr - int
515 returns: str - description of the tte + additional informaiton based on verbose_level
516 """
517 pte_base = kern.PhysToKernelVirt(tte & 0xFFFFFC00)
518 pte_index = (vaddr >> 12) & 0xFF
519 pte_base_val = kern.GetValueFromAddress(pte_base, 'pt_entry_t *')
520 pte = pte_base_val[pte_index]
521 out_string = ''
522 if verbose_level >= vSCRIPT:
523 out_string += "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte), tte)
524 # bit [1:0] evaluated in PmapWalkARM
525 # NS bit 3
526 if tte & 0x8:
527 out_string += ' no-secure'
528 else:
529 out_string += ' secure'
530 #Domain bit [8:5]
531 out_string += " domain({:d})".format(((tte & 0x1e0) >> 5))
532 # IMP bit 9
533 out_string += " imp({:d})".format( ((tte & 0x200) >> 9))
534 out_string += "\n"
535 if verbose_level >= vSCRIPT:
536 out_string += "second-level table (index {:d}):\n".format(pte_index)
537 if verbose_level >= vDETAIL:
538 for i in range(256):
539 tmp = pte_base_val[i]
540 out_string += "{0: <#020x}:\t{1: <#020x}\n".format(addressof(tmp), unsigned(tmp))
541
542 paddr = 0
543 if pte & 0x2:
544 paddr = (unsigned(pte) & 0xFFFFF000) | (vaddr & 0xFFF)
545
546 if verbose_level >= vSCRIPT:
547 out_string += " {0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(pte), unsigned(pte))
548 if (pte & 0x3) == 0x0:
549 out_string += " invalid"
550 else:
551 if (pte & 0x3) == 0x1:
552 out_string += " large"
553 # XN bit 15
554 if pte & 0x8000 == 0x8000:
555 out_string+= " no-execute"
556 else:
557 out_string += " execute"
558 else:
559 out_string += " small"
560 # XN bit 0
561 if (pte & 0x1) == 0x01:
562 out_string += " no-execute"
563 else:
564 out_string += " execute"
565 # B bit 2
566 b_bit = (pte & 0x4) >> 2
567 c_bit = (pte & 0x8) >> 3
568 # AP bit 9 and [5:4], merged to a single 3-bit value
569 access = (pte & 0x30) >> 4 | (pte & 0x200) >> 7
570 out_string += xnudefines.arm_level2_access_strings[access]
571
572 #TEX bit [14:12] for large, [8:6] for small
573 tex_bits = ((pte & 0x1c0) >> 6)
574 if (pte & 0x3) == 0x1:
575 tex_bits = ((pte & 0x7000) >> 12)
576
577 # Print TEX, C , B alltogether
578 out_string += " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format(
579 1 if (tex_bits & 0x4) else 0,
580 1 if (tex_bits & 0x2) else 0,
581 1 if (tex_bits & 0x1) else 0,
582 c_bit,
583 b_bit
584 )
585 # S bit 10
586 if pte & 0x400 :
587 out_string += " shareable"
588 else:
589 out_string += " not-shareable"
590
591 # nG bit 11
592 if pte & 0x800:
593 out_string += " not-global"
594 else:
595 out_string += " global"
596 print out_string
597 return paddr
598 #end of level 2 walking of arm
599
600
601 def PmapWalkARM(pmap, vaddr, verbose_level = vHUMAN):
602 """ Pmap walking for ARM kernel.
603 params:
604 pmapval: core.value - representing pmap_t in kernel
605 vaddr: int - integer representing virtual address to walk
606 """
607 paddr = 0
608 # shift by TTESHIFT (20) to get tte index
609 tte_index = ((vaddr - unsigned(pmap.min)) >> 20 )
610 tte = pmap.tte[tte_index]
611 if verbose_level >= vSCRIPT:
612 print "First-level table (index {:d}):".format(tte_index)
613 if verbose_level >= vDETAIL:
614 for i in range(0, 4096):
615 ptr = unsigned(addressof(pmap.tte[i]))
616 val = unsigned(pmap.tte[i])
617 print "{0: <#020x}:\t {1: <#020x}".format(ptr, val)
618 if (tte & 0x3) == 0x1:
619 paddr = _PmapWalkARMLevel2(tte, vaddr, verbose_level)
620 elif (tte & 0x3) == 0x2 :
621 paddr = _PmapWalkARMLevel1Section(tte, vaddr, verbose_level)
622 else:
623 paddr = 0
624 if verbose_level >= vSCRIPT:
625 print "Invalid First-Level Translation Table Entry: {0: #020x}".format(tte)
626
627 if verbose_level >= vHUMAN:
628 if paddr:
629 print "Translation of {:#x} is {:#x}.".format(vaddr, paddr)
630 else:
631 print "(no translation)"
632
633 return paddr
634
635 def PmapWalkX86_64(pmapval, vaddr, verbose_level = vSCRIPT):
636 """
637 params: pmapval - core.value representing pmap_t in kernel
638 vaddr: int - int representing virtual address to walk
639 """
640 if pmapval.pm_cr3 != 0:
641 if verbose_level > vHUMAN:
642 print "Using normal Intel PMAP from pm_cr3\n"
643 return _PmapL4Walk(pmapval.pm_cr3, vaddr, 0, config['verbosity'])
644 else:
645 if verbose_level > vHUMAN:
646 print "Using EPT pmap from pm_eptp\n"
647 return _PmapL4Walk(pmapval.pm_eptp, vaddr, 1, config['verbosity'])
648
649 def assert_64bit(val):
650 assert(val < 2**64)
651
652 ARM64_TTE_SIZE = 8
653 ARM64_VMADDR_BITS = 48
654
655 def PmapBlockOffsetMaskARM64(level):
656 assert level >= 1 and level <= 3
657 page_size = kern.globals.arm_hardware_page_size
658 ttentries = (page_size / ARM64_TTE_SIZE)
659 return page_size * (ttentries ** (3 - level)) - 1
660
661 def PmapBlockBaseMaskARM64(level):
662 assert level >= 1 and level <= 3
663 page_size = kern.globals.arm_hardware_page_size
664 return ((1 << ARM64_VMADDR_BITS) - 1) & ~PmapBlockOffsetMaskARM64(level)
665
666 def PmapIndexMaskARM64(level):
667 assert level >= 1 and level <= 3
668 page_size = kern.globals.arm_hardware_page_size
669 ttentries = (page_size / ARM64_TTE_SIZE)
670 return page_size * (ttentries ** (3 - level) * (ttentries - 1))
671
672 def PmapIndexDivideARM64(level):
673 assert level >= 1 and level <= 3
674 page_size = kern.globals.arm_hardware_page_size
675 ttentries = (page_size / ARM64_TTE_SIZE)
676 return page_size * (ttentries ** (3 - level))
677
678 def PmapTTnIndexARM64(vaddr, level):
679 assert(type(vaddr) in (long, int))
680 assert_64bit(vaddr)
681
682 return (vaddr & PmapIndexMaskARM64(level)) // PmapIndexDivideARM64(level)
683
684 def PmapDecodeTTEARM64(tte, level):
685 assert(type(tte) == long)
686 assert(type(level) == int)
687 assert_64bit(tte)
688
689 if tte & 0x1 == 0x1:
690 if (tte & 0x2 == 0x2) and (level != 0x3):
691 print "Type = Table pointer."
692 print "Table addr = {:#x}.".format(tte & 0xfffffffff000)
693 print "PXN = {:#x}.".format((tte >> 59) & 0x1)
694 print "XN = {:#x}.".format((tte >> 60) & 0x1)
695 print "AP = {:#x}.".format((tte >> 61) & 0x3)
696 print "NS = {:#x}".format(tte >> 63)
697 else:
698 print "Type = Block."
699 print "AttrIdx = {:#x}.".format((tte >> 2) & 0x7)
700 print "NS = {:#x}.".format((tte >> 5) & 0x1)
701 print "AP = {:#x}.".format((tte >> 6) & 0x3)
702 print "SH = {:#x}.".format((tte >> 8) & 0x3)
703 print "AF = {:#x}.".format((tte >> 10) & 0x1)
704 print "nG = {:#x}.".format((tte >> 11) & 0x1)
705 print "HINT = {:#x}.".format((tte >> 52) & 0x1)
706 print "PXN = {:#x}.".format((tte >> 53) & 0x1)
707 print "XN = {:#x}.".format((tte >> 54) & 0x1)
708 print "SW Use = {:#x}.".format((tte >> 55) & 0xf)
709 else:
710 print "Invalid."
711
712 return
713
714 def PmapWalkARM64(pmap, vaddr, verbose_level = vHUMAN):
715 assert(type(pmap) == core.cvalue.value)
716 assert(type(vaddr) in (long, int))
717 page_size = kern.globals.arm_hardware_page_size
718 page_offset_mask = (page_size - 1)
719 page_base_mask = ((1 << ARM64_VMADDR_BITS) - 1) & (~page_offset_mask)
720
721 assert_64bit(vaddr)
722 paddr = -1
723
724 tt1_index = PmapTTnIndexARM64(vaddr, 1)
725 tt2_index = PmapTTnIndexARM64(vaddr, 2)
726 tt3_index = PmapTTnIndexARM64(vaddr, 3)
727
728 # L1
729 tte = long(unsigned(pmap.tte[tt1_index]))
730 assert(type(tte) == long)
731 assert_64bit(tte)
732
733 if verbose_level >= vSCRIPT:
734 print "L1 entry: {:#x}".format(tte)
735 if verbose_level >= vDETAIL:
736 PmapDecodeTTEARM64(tte, 1)
737
738 if tte & 0x1 == 0x1:
739 # Check for L1 block entry
740 if tte & 0x2 == 0x0:
741 # Handle L1 block entry
742 paddr = tte & PmapBlockBaseMaskARM64(1)
743 paddr = paddr | (vaddr & PmapBlockOffsetMaskARM64(1))
744 print "phys: {:#x}".format(paddr)
745 else:
746 # Handle L1 table entry
747 l2_phys = (tte & page_base_mask) + (ARM64_TTE_SIZE * tt2_index)
748 assert(type(l2_phys) == long)
749
750 l2_virt = kern.PhysToKernelVirt(l2_phys)
751 assert(type(l2_virt) == long)
752
753 if verbose_level >= vDETAIL:
754 print "L2 physical address: {:#x}. L2 virtual address: {:#x}".format(l2_phys, l2_virt)
755
756 # L2
757 ttep = kern.GetValueFromAddress(l2_virt, "tt_entry_t*")
758 tte = long(unsigned(dereference(ttep)))
759 assert(type(tte) == long)
760
761 if verbose_level >= vSCRIPT:
762 print "L2 entry: {:#0x}".format(tte)
763 if verbose_level >= vDETAIL:
764 PmapDecodeTTEARM64(tte, 2)
765
766 if tte & 0x1 == 0x1:
767 # Check for L2 block entry
768 if tte & 0x2 == 0x0:
769 # Handle L2 block entry
770 paddr = tte & PmapBlockBaseMaskARM64(2)
771 paddr = paddr | (vaddr & PmapBlockOffsetMaskARM64(2))
772 else:
773 # Handle L2 table entry
774 l3_phys = (tte & page_base_mask) + (ARM64_TTE_SIZE * tt3_index)
775 assert(type(l3_phys) == long)
776
777 l3_virt = kern.PhysToKernelVirt(l3_phys)
778 assert(type(l3_virt) == long)
779
780 if verbose_level >= vDETAIL:
781 print "L3 physical address: {:#x}. L3 virtual address: {:#x}".format(l3_phys, l3_virt)
782
783 # L3
784 ttep = kern.GetValueFromAddress(l3_virt, "tt_entry_t*")
785 tte = long(unsigned(dereference(ttep)))
786 assert(type(tte) == long)
787
788 if verbose_level >= vSCRIPT:
789 print "L3 entry: {:#0x}".format(tte)
790 if verbose_level >= vDETAIL:
791 PmapDecodeTTEARM64(tte, 3)
792
793 if tte & 0x3 == 0x3:
794 paddr = tte & page_base_mask
795 paddr = paddr | (vaddr & page_offset_mask)
796 elif verbose_level >= vHUMAN:
797 print "L3 entry invalid: {:#x}\n".format(tte)
798 elif verbose_level >= vHUMAN: # tte & 0x1 == 0x1
799 print "L2 entry invalid: {:#x}\n".format(tte)
800 elif verbose_level >= vHUMAN:
801 print "L1 entry invalid: {:#x}\n".format(tte)
802
803 if verbose_level >= vHUMAN:
804 if paddr:
805 print "Translation of {:#x} is {:#x}.".format(vaddr, paddr)
806 else:
807 print "(no translation)"
808
809 return paddr
810
811 def PmapWalk(pmap, vaddr, verbose_level = vHUMAN):
812 if kern.arch == 'x86_64':
813 return PmapWalkX86_64(pmap, vaddr, verbose_level)
814 elif kern.arch == 'arm':
815 return PmapWalkARM(pmap, vaddr, verbose_level)
816 elif kern.arch == 'arm64':
817 return PmapWalkARM64(pmap, vaddr, verbose_level)
818 else:
819 raise NotImplementedError("PmapWalk does not support {0}".format(kern.arch))
820
821 @lldb_command('pmap_walk')
822 def PmapWalkHelper(cmd_args=None):
823 """ Perform a page-table walk in <pmap> for <virtual_address>.
824 Syntax: (lldb) pmap_walk <pmap> <virtual_address> [-v] [-e]
825 Multiple -v's can be specified for increased verbosity
826 """
827 if cmd_args == None or len(cmd_args) < 2:
828 raise ArgumentError("Too few arguments to pmap_walk.")
829
830 pmap = kern.GetValueAsType(cmd_args[0], 'pmap_t')
831 addr = unsigned(kern.GetValueFromAddress(cmd_args[1], 'void *'))
832 PmapWalk(pmap, addr, config['verbosity'])
833 return