]>
Commit | Line | Data |
---|---|---|
39236c6e A |
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 | def _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 | ||
286 | def _PmapL4Walk(pmap_addr_val,vaddr, verbose_level = vSCRIPT): | |
287 | """ Walk the l4 pmap entry. | |
288 | params: pmap_addr_val - core.value representing kernel data of type pmap_addr_t | |
289 | vaddr : int - virtual address to walk | |
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 | ||
339 | def _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 | ||
405 | def _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 | ||
496 | def 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 | ||
530 | def 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 | ||
537 | def assert_64bit(val): | |
538 | assert(val < 2**64) | |
539 | ||
540 | def PmapWalk(pmap, vaddr, verbose_level = vHUMAN): | |
541 | if kern.arch == 'x86_64': | |
542 | return PmapWalkX86_64(pmap, vaddr) | |
543 | elif kern.arch == 'arm': | |
544 | return PmapWalkARM(pmap, vaddr, verbose_level) | |
545 | else: | |
546 | raise NotImplementedError("PmapWalk does not support {0}".format(kern.arch)) | |
547 | ||
548 | @lldb_command('pmap_walk') | |
549 | def PmapWalkHelper(cmd_args=None): | |
550 | """ Perform a page-table walk in <pmap> for <virtual_address>. | |
551 | Syntax: (lldb) pmap_walk <pmap> <virtual_address> [-v] | |
552 | Multiple -v's can be specified for increased verbosity | |
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 |