]> git.saurik.com Git - apple/xnu.git/blame - tools/lldbmacros/pmap.py
xnu-2422.90.20.tar.gz
[apple/xnu.git] / tools / lldbmacros / pmap.py
CommitLineData
39236c6e
A
1from xnu import *
2import xnudefines
3from kdp import *
4from utils import *
5
6def 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')
32def 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
49lldb_alias('readphys8', 'readphys 8 ')
50lldb_alias('readphys16', 'readphys 16 ')
51lldb_alias('readphys32', 'readphys 32 ')
52lldb_alias('readphys64', 'readphys 64 ')
53
54def 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
103def 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
153def 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')
172def 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
191lldb_alias('writephys8', 'writephys 8 ')
192lldb_alias('writephys16', 'writephys 16 ')
193lldb_alias('writephys32', 'writephys 32 ')
194lldb_alias('writephys64', 'writephys 64 ')
195
196def _PT_Step(paddr, index, verbose_level = vSCRIPT):
197 """
198 Step to lower-level page table and print attributes
199 paddr: current page table entry physical address
200 index: current page table entry index (0..511)
201 verbose_level: vHUMAN: print nothing
202 vSCRIPT: print basic information
203 vDETAIL: print basic information and hex table dump
204 returns: (pt_paddr, pt_valid, pt_large)
205 pt_paddr: next level page table entry physical address
206 or null if invalid
207 pt_valid: 1 if $kgm_pt_paddr is valid, 0 if the walk
208 should be aborted
209 pt_large: 1 if kgm_pt_paddr is a page frame address
210 of a large page and not another page table entry
211 """
212 entry_addr = paddr + (8 * index)
213 entry = ReadPhysInt(entry_addr, 64, xnudefines.lcpu_self )
214 out_string = ''
215 if verbose_level >= vDETAIL:
216 for pte_loop in range(0, 512):
217 paddr_tmp = paddr + (8 * pte_loop)
218 out_string += "{0: <#020x}:\t {1: <#020x}\n".format(paddr_tmp, ReadPhysInt(paddr_tmp, 64, xnudefines.lcpu_self))
219 paddr_mask = ~((0xfff<<52) | 0xfff)
220 paddr_large_mask = ~((0xfff<<52) | 0x1fffff)
221 pt_valid = False
222 pt_large = False
223 pt_paddr = 0
224 if verbose_level < vSCRIPT:
225 if entry & 0x1 :
226 pt_valid = True
227 pt_large = False
228 pt_paddr = entry & paddr_mask
229 if entry & (0x1 <<7):
230 pt_large = True
231 pt_paddr = entry & paddr_large_mask
232 else:
233 out_string+= "{0: <#020x}:\n\t{1:#020x}\n\t".format(entry_addr, entry)
234 if entry & 0x1:
235 out_string += " valid"
236 pt_paddr = entry & paddr_mask
237 pt_valid = True
238 else:
239 out_string += " invalid"
240 pt_paddr = 0
241 pt_valid = False
242 #Stop decoding other bits
243 entry = 0
244 if entry & (0x1 << 1):
245 out_string += " writable"
246 else:
247 out_string += " read-only"
248
249 if entry & (0x1 << 2):
250 out_string += " user"
251 else:
252 out_string += " supervisor"
253
254 if entry & (0x1 << 3):
255 out_string += " PWT"
256
257 if entry & (0x1 << 4):
258 out_string += " PCD"
259
260 if entry & (0x1 << 5):
261 out_string += " accessed"
262
263 if entry & (0x1 << 6):
264 out_string += " dirty"
265
266 if entry & (0x1 << 7):
267 out_string += " large"
268 pt_large = True
269 else:
270 pt_large = False
271
272 if entry & (0x1 << 8):
273 out_string += " global"
274
275 if entry & (0x3 << 9):
276 out_string += " avail:{0:x}".format((entry >> 9) & 0x3)
277
278 if entry & (0x1 << 63):
279 out_string += " noexec"
280 print out_string
281 return (pt_paddr, pt_valid, pt_large)
282
283
284
285
286def _PmapL4Walk(pmap_addr_val,vaddr, verbose_level = vSCRIPT):
287 """ Walk the l4 pmap entry.
288 params: pmap_addr_val - core.value representing kernel data of type pmap_addr_t
289 vaddr : int - virtual address to walk
290 """
291 is_cpu64_bit = int(kern.globals.cpu_64bit)
292 pt_paddr = unsigned(pmap_addr_val)
293 pt_valid = (unsigned(pmap_addr_val) != 0)
294 pt_large = 0
295 pframe_offset = 0
296 if pt_valid and is_cpu64_bit:
297 # Lookup bits 47:39 of linear address in PML4T
298 pt_index = (vaddr >> 39) & 0x1ff
299 pframe_offset = vaddr & 0x7fffffffff
300 if verbose_level > vHUMAN :
301 print "pml4 (index {0:d}):".format(pt_index)
302 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
303 if pt_valid:
304 # Lookup bits 38:30 of the linear address in PDPT
305 pt_index = (vaddr >> 30) & 0x1ff
306 pframe_offset = vaddr & 0x3fffffff
307 if verbose_level > vHUMAN:
308 print "pdpt (index {0:d}):".format(pt_index)
309 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
310 if pt_valid and not pt_large:
311 #Lookup bits 29:21 of the linear address in PDPT
312 pt_index = (vaddr >> 21) & 0x1ff
313 pframe_offset = vaddr & 0x1fffff
314 if verbose_level > vHUMAN:
315 print "pdt (index {0:d}):".format(pt_index)
316 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
317 if pt_valid and not pt_large:
318 #Lookup bits 20:21 of linear address in PT
319 pt_index = (vaddr >> 12) & 0x1ff
320 pframe_offset = vaddr & 0xfff
321 if verbose_level > vHUMAN:
322 print "pt (index {0:d}):".format(pt_index)
323 (pt_paddr, pt_valid, pt_large) = _PT_Step(pt_paddr, pt_index, verbose_level)
324 paddr = 0
325 paddr_isvalid = False
326 if pt_valid:
327 paddr = pt_paddr + pframe_offset
328 paddr_isvalid = True
329
330 if verbose_level > vHUMAN:
331 if paddr_isvalid:
332 pvalue = ReadPhysInt(paddr, 32, xnudefines.lcpu_self)
333 print "phys {0: <#020x}: {1: <#020x}".format(paddr, pvalue)
334 else:
335 print "no translation"
336
337 return
338
339def _PmapWalkARMLevel1Section(tte, vaddr, verbose_level = vSCRIPT):
340 paddr = 0
341 out_string = ""
342 #Supersection or just section?
343 if (tte & 0x40000) == 0x40000:
344 paddr = ( (tte & 0xFF000000) | (vaddr & 0x00FFFFFF) )
345 else:
346 paddr = ( (tte & 0xFFF00000) | (vaddr & 0x000FFFFF) )
347
348 if verbose_level >= vSCRIPT:
349 out_string += "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte), tte)
350 #bit [1:0] evaluated in PmapWalkARM
351 # B bit 2
352 b_bit = (tte & 0x4) >> 2
353 # C bit 3
354 c_bit = (tte & 0x8) >> 3
355 #XN bit 4
356 if (tte & 0x10) :
357 out_string += "no-execute"
358 else:
359 out_string += "execute"
360 #Domain bit [8:5] if not supersection
361 if (tte & 0x40000) == 0x0:
362 out_string += " domain ({:d})".format(((tte & 0x1e0) >> 5) )
363 #IMP bit 9
364 out_string += " imp({:d})".format( ((tte & 0x200) >> 9) )
365 # AP bit 15 and [11:10] merged to a single 3 bit value
366 access = ( (tte & 0xc00) >> 10 ) | ((tte & 0x8000) >> 13)
367 out_string += xnudefines.arm_level2_access_strings[access]
368
369 #TEX bit [14:12]
370 tex_bits = ((tte & 0x7000) >> 12)
371 #Print TEX, C , B all together
372 out_string += " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format(
373 1 if (tex_bits & 0x4) else 0,
374 1 if (tex_bits & 0x2) else 0,
375 1 if (tex_bits & 0x1) else 0,
376 c_bit,
377 b_bit
378 )
379 # S bit 16
380 if tte & 0x10000:
381 out_string += " shareable"
382 else:
383 out_string += " not-shareable"
384 # nG bit 17
385 if tte & 0x20000 :
386 out_string += " not-global"
387 else:
388 out_string += " global"
389 # Supersection bit 18
390 if tte & 0x40000:
391 out_string += " supersection"
392 else:
393 out_string += " section"
394 #NS bit 19
395 if tte & 0x80000 :
396 out_string += " no-secure"
397 else:
398 out_string += " secure"
399
400 print out_string
401 return paddr
402
403
404
405def _PmapWalkARMLevel2(tte, vaddr, verbose_level = vSCRIPT):
406 """ Pmap walk the level 2 tte.
407 params:
408 tte - value object
409 vaddr - int
410 returns: str - description of the tte + additional informaiton based on verbose_level
411 """
412 pte_base = kern.PhysToKernelVirt(tte & 0xFFFFFC00)
413 pte_index = (vaddr >> 12) & 0xFF
414 pte_base_val = kern.GetValueFromAddress(pte_base, 'pt_entry_t *')
415 pte = pte_base_val[pte_index]
416 out_string = ''
417 if verbose_level >= vSCRIPT:
418 out_string += "{0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(tte), tte)
419 # bit [1:0] evaluated in PmapWalkARM
420 # NS bit 3
421 if tte & 0x8:
422 out_string += ' no-secure'
423 else:
424 out_string += ' secure'
425 #Domain bit [8:5]
426 out_string += " domain({:d})".format(((tte & 0x1e0) >> 5))
427 # IMP bit 9
428 out_string += " imp({:d})".format( ((tte & 0x200) >> 9))
429 out_string += "\n"
430 if verbose_level >= vSCRIPT:
431 out_string += "second-level table (index {:d}):\n".format(pte_index)
432 if verbose_level >= vDETAIL:
433 for i in range(256):
434 tmp = pte_base_val[i]
435 out_string += "{0: <#020x}:\t{1: <#020x}\n".format(addressof(tmp), unsigned(tmp))
436
437 paddr = 0
438 if pte & 0x2:
439 paddr = (unsigned(pte) & 0xFFFFF000) | (vaddr & 0xFFF)
440
441 if verbose_level >= vSCRIPT:
442 out_string += " {0: <#020x}\n\t{1: <#020x}\n\t".format(addressof(pte), unsigned(pte))
443 if (pte & 0x3) == 0x0:
444 out_string += " invalid"
445 else:
446 if (pte & 0x3) == 0x1:
447 out_string += " large"
448 # XN bit 15
449 if pte & 0x8000 == 0x8000:
450 out_string+= " no-execute"
451 else:
452 out_string += " execute"
453 else:
454 out_string += " small"
455 # XN bit 0
456 if (pte & 0x1) == 0x01:
457 out_string += " no-execute"
458 else:
459 out_string += " execute"
460 # B bit 2
461 b_bit = (pte & 0x4) >> 2
462 c_bit = (pte & 0x8) >> 3
463 # AP bit 9 and [5:4], merged to a single 3-bit value
464 access = (pte & 0x30) >> 4 | (pte & 0x200) >> 7
465 out_string += xnudefines.arm_level2_access_strings[access]
466
467 #TEX bit [14:12] for large, [8:6] for small
468 tex_bits = ((pte & 0x1c0) >> 6)
469 if (pte & 0x3) == 0x1:
470 tex_bits = ((pte & 0x7000) >> 12)
471
472 # Print TEX, C , B alltogether
473 out_string += " TEX:C:B({:d}{:d}{:d}:{:d}:{:d})".format(
474 1 if (tex_bits & 0x4) else 0,
475 1 if (tex_bits & 0x2) else 0,
476 1 if (tex_bits & 0x1) else 0,
477 c_bit,
478 b_bit
479 )
480 # S bit 10
481 if pte & 0x400 :
482 out_string += " shareable"
483 else:
484 out_string += " not-shareable"
485
486 # nG bit 11
487 if pte & 0x800:
488 out_string += " not-global"
489 else:
490 out_string += " global"
491 print out_string
492 return paddr
493 #end of level 2 walking of arm
494
495
496def PmapWalkARM(pmap, vaddr, verbose_level = vHUMAN):
497 """ Pmap walking for ARM kernel.
498 params:
499 pmapval: core.value - representing pmap_t in kernel
500 vaddr: int - integer representing virtual address to walk
501 """
502 paddr = 0
503 # shift by TTESHIFT (20) to get tte index
504 tte_index = ((vaddr - unsigned(pmap.min)) >> 20 )
505 tte = pmap.tte[tte_index]
506 if verbose_level >= vSCRIPT:
507 print "First-level table (index {:d}):".format(tte_index)
508 if verbose_level >= vDETAIL:
509 for i in range(0, 4096):
510 ptr = unsigned(addressof(pmap.tte[i]))
511 val = unsigned(pmap.tte[i])
512 print "{0: <#020x}:\t {1: <#020x}".format(ptr, val)
513 if (tte & 0x3) == 0x1:
514 paddr = _PmapWalkARMLevel2(tte, vaddr, verbose_level)
515 elif (tte & 0x3) == 0x2 :
516 paddr = _PmapWalkARMLevel1Section(tte, vaddr, verbose_level)
517 else:
518 paddr = 0
519 if verbose_level >= vSCRIPT:
520 print "Invalid First-Level Translation Table Entry: {0: #020x}".format(tte)
521
522 if verbose_level >= vHUMAN:
523 if paddr:
524 print "Translation of {:#x} is {:#x}.".format(vaddr, paddr)
525 else:
526 print "(no translation)"
527
528 return paddr
529
530def PmapWalkX86_64(pmapval, vaddr):
531 """
532 params: pmapval - core.value representing pmap_t in kernel
533 vaddr: int - int representing virtual address to walk
534 """
535 _PmapL4Walk(pmapval.pm_cr3, vaddr, config['verbosity'])
536
537def assert_64bit(val):
538 assert(val < 2**64)
539
540def PmapWalk(pmap, vaddr, verbose_level = vHUMAN):
541 if kern.arch == 'x86_64':
542 return PmapWalkX86_64(pmap, vaddr)
543 elif kern.arch == 'arm':
544 return PmapWalkARM(pmap, vaddr, verbose_level)
545 else:
546 raise NotImplementedError("PmapWalk does not support {0}".format(kern.arch))
547
548@lldb_command('pmap_walk')
549def PmapWalkHelper(cmd_args=None):
550 """ Perform a page-table walk in <pmap> for <virtual_address>.
551 Syntax: (lldb) pmap_walk <pmap> <virtual_address> [-v]
552 Multiple -v's can be specified for increased verbosity
553 """
554 if cmd_args == None or len(cmd_args) < 2:
555 raise ArgumentError("Too few arguments to pmap_walk.")
556
557 pmap = kern.GetValueAsType(cmd_args[0], 'pmap_t')
558 addr = unsigned(kern.GetValueFromAddress(cmd_args[1], 'void *'))
559 PmapWalk(pmap, addr, config['verbosity'])
560 return