]> git.saurik.com Git - apple/xnu.git/blame - tools/lldbmacros/memory.py
xnu-3247.1.106.tar.gz
[apple/xnu.git] / tools / lldbmacros / memory.py
CommitLineData
39236c6e
A
1
2""" Please make sure you read the README file COMPLETELY BEFORE reading anything below.
fe8ab488 3 It is very critical that you read coding guidelines in Section E in README file.
39236c6e
A
4"""
5from xnu import *
fe8ab488
A
6import sys
7import shlex
39236c6e
A
8from utils import *
9import xnudefines
10from process import *
11
12# Macro: memstats
13@lldb_command('memstats')
14def Memstats(cmd_args=None):
15 """ Prints out a summary of various memory statistics. In particular vm_page_wire_count should be greater than 2K or you are under memory pressure.
16 """
17 try:
18 print "memorystatus_level: {: >10d}".format(kern.globals.memorystatus_level)
19 except ValueError:
20 pass
21 try:
22 print "memorystatus_available_pages: {: >10d}".format(kern.globals.memorystatus_available_pages)
23 except ValueError:
24 pass
25 print "vm_page_throttled_count: {: >10d}".format(kern.globals.vm_page_throttled_count)
26 print "vm_page_active_count: {: >10d}".format(kern.globals.vm_page_active_count)
27 print "vm_page_inactive_count: {: >10d}".format(kern.globals.vm_page_inactive_count)
28 print "vm_page_wire_count: {: >10d}".format(kern.globals.vm_page_wire_count)
29 print "vm_page_free_count: {: >10d}".format(kern.globals.vm_page_free_count)
30 print "vm_page_purgeable_count: {: >10d}".format(kern.globals.vm_page_purgeable_count)
31 print "vm_page_inactive_target: {: >10d}".format(kern.globals.vm_page_inactive_target)
32 print "vm_page_free_target: {: >10d}".format(kern.globals.vm_page_free_target)
33 print "inuse_ptepages_count: {: >10d}".format(kern.globals.inuse_ptepages_count)
34 print "vm_page_free_reserved: {: >10d}".format(kern.globals.vm_page_free_reserved)
35
36@xnudebug_test('test_memstats')
37def TestMemstats(kernel_target, config, lldb_obj, isConnected ):
38 """ Test the functionality of memstats command
39 returns
40 - False on failure
41 - True on success
42 """
43 if not isConnected:
44 print "Target is not connected. Cannot test memstats"
45 return False
46 res = lldb.SBCommandReturnObject()
47 lldb_obj.debugger.GetCommandInterpreter().HandleCommand("memstats", res)
48 result = res.GetOutput()
49 if result.split(":")[1].strip().find('None') == -1 :
50 return True
51 else:
52 return False
53
54# EndMacro: memstats
55
56# Macro: showmemorystatus
57def CalculateLedgerPeak(phys_footprint_entry):
58 """ Internal function to calculate ledger peak value for the given phys footprint entry
59 params: phys_footprint_entry - value representing struct ledger_entry *
60 return: value - representing the ledger peak for the given phys footprint entry
61 """
62 now = kern.globals.sched_tick / 20
63 ledger_peak = phys_footprint_entry.le_credit - phys_footprint_entry.le_debit
64 if (now - phys_footprint_entry._le.le_peaks[0].le_time <= 1) and (phys_footprint_entry._le.le_peaks[0].le_max > ledger_peak):
65 ledger_peak = phys_footprint_entry._le.le_peaks[0].le_max
66 if (now - phys_footprint_entry._le.le_peaks[1].le_time <= 1) and (phys_footprint_entry._le.le_peaks[1].le_max > ledger_peak):
67 ledger_peak = phys_footprint_entry._le.le_peaks[1].le_max
68 return ledger_peak
69
70@header("{: >8s} {: >22s} {: >22s} {: >11s} {: >11s} {: >12s} {: >10s} {: >13s} {: ^10s} {: >8s} {: <20s}\n".format(
71'pid', 'effective priority', 'requested priority', 'state', 'user_data', 'physical', 'iokit', 'footprint',
72'spike', 'limit', 'command'))
73def GetMemoryStatusNode(proc_val):
74 """ Internal function to get memorystatus information from the given proc
75 params: proc - value representing struct proc *
76 return: str - formatted output information for proc object
77 """
78 out_str = ''
79 task_val = Cast(proc_val.task, 'task *')
80 task_ledgerp = task_val.ledger
81
82 task_physmem_footprint_ledger_entry = task_ledgerp.l_entries[kern.globals.task_ledgers.phys_mem]
fe8ab488 83 task_iokit_footprint_ledger_entry = task_ledgerp.l_entries[kern.globals.task_ledgers.iokit_mapped]
39236c6e
A
84 task_phys_footprint_ledger_entry = task_ledgerp.l_entries[kern.globals.task_ledgers.phys_footprint]
85 page_size = kern.globals.page_size
86
87 phys_mem_footprint = (task_physmem_footprint_ledger_entry.le_credit - task_physmem_footprint_ledger_entry.le_debit) / page_size
88 iokit_footprint = (task_iokit_footprint_ledger_entry.le_credit - task_iokit_footprint_ledger_entry.le_debit) / page_size
89 phys_footprint = (task_phys_footprint_ledger_entry.le_credit - task_phys_footprint_ledger_entry.le_debit) / page_size
90 phys_footprint_limit = task_phys_footprint_ledger_entry.le_limit / page_size
91 ledger_peak = CalculateLedgerPeak(task_phys_footprint_ledger_entry)
92 phys_footprint_spike = ledger_peak / page_size
93
94 format_string = '{0: >8d} {1: >22d} {2: >22d} {3: #011x} {4: #011x} {5: >12d} {6: >10d} {7: >13d}'
95 out_str += format_string.format(proc_val.p_pid, proc_val.p_memstat_effectivepriority,
96 proc_val.p_memstat_requestedpriority, proc_val.p_memstat_state, proc_val.p_memstat_userdata,
97 phys_mem_footprint, iokit_footprint, phys_footprint)
98 if phys_footprint != phys_footprint_spike:
99 out_str += "{: ^12d}".format(phys_footprint_spike)
100 else:
101 out_str += "{: ^12s}".format('-')
102 out_str += "{: 8d} {: <20s}\n".format(phys_footprint_limit, proc_val.p_comm)
103 return out_str
104
105@lldb_command('showmemorystatus')
106def ShowMemoryStatus(cmd_args=None):
107 """ Routine to display each entry in jetsam list with a summary of pressure statistics
108 Usage: showmemorystatus
109 """
110 bucket_index = 0
111 bucket_count = 20
112 print GetMemoryStatusNode.header
113 print "{: >91s} {: >10s} {: >13s} {: ^10s} {: >8s}\n".format("(pages)", "(pages)", "(pages)",
114 "(pages)", "(pages)")
115 while bucket_index < bucket_count:
116 current_bucket = kern.globals.memstat_bucket[bucket_index]
117 current_list = current_bucket.list
118 current_proc = Cast(current_list.tqh_first, 'proc *')
119 while unsigned(current_proc) != 0:
120 print GetMemoryStatusNode(current_proc)
121 current_proc = current_proc.p_memstat_list.tqe_next
122 bucket_index += 1
123 print "\n\n"
124 Memstats()
125
126# EndMacro: showmemorystatus
127
128# Macro: zprint
129
130@lldb_type_summary(['zone','zone_t'])
3e170ce0
A
131@header("{:^18s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s}({:>6s} {:>6s} {:>6s}) {:^15s} {:<20s}".format(
132'ZONE', 'TOT_SZ', 'PAGE_COUNT', 'ALLOC_ELTS', 'FREE_ELTS', 'FREE_SZ', 'ELT_SZ', 'ALLOC', 'ELTS', 'PGS', 'WASTE', 'FLAGS', 'NAME'))
39236c6e
A
133def GetZoneSummary(zone):
134 """ Summarize a zone with important information. See help zprint for description of each field
135 params:
136 zone: value - obj representing a zone in kernel
137 returns:
138 str - summary of the zone
139 """
140 out_string = ""
3e170ce0
A
141 format_string = '{:#018x} {:10d} {:10d} {:10d} {:10d} {:10d} {:10d} {:10d} {:6d} {:6d} {:6d} {markings} {name:s} '
142 pagesize = kern.globals.page_size
39236c6e 143
3e170ce0 144 free_elements = zone.countfree
39236c6e
A
145 free_size = free_elements * zone.elem_size
146
39236c6e 147 alloc_pages = zone.alloc_size / pagesize
3e170ce0
A
148 if zone.use_page_list :
149 metadata_size = sizeof('struct zone_page_metadata')
150 metadata_offset = metadata_size
151 if ((metadata_size % zone.elem_size) != 0) :
152 metadata_offset += zone.elem_size - (metadata_size % zone.elem_size)
153 alloc_count = ((pagesize - metadata_offset) / zone.elem_size) * alloc_pages
154 alloc_waste = metadata_offset * alloc_pages
155 else :
156 alloc_count = zone.alloc_size / zone.elem_size
157 alloc_waste = zone.alloc_size % zone.elem_size
158
39236c6e 159 marks = [
3e170ce0
A
160 ["collectable", "C"],
161 ["expandable", "X"],
162 ["noencrypt", "$"],
163 ["caller_acct", "@"],
164 ["exhaustible", "H"],
165 ["allows_foreign", "F"],
166 ["async_prio_refill", "R"],
167 ["no_callout", "O"],
168 ["zleak_on", "L"],
169 ["doing_alloc_without_vm_priv", "A"],
170 ["doing_alloc_with_vm_priv", "S"],
171 ["waiting", "W"],
172 ["doing_gc", "G"],
173 ["use_page_list", "P"]
39236c6e
A
174 ]
175 if kern.arch == 'x86_64':
176 marks.append(["gzalloc_exempt", "M"])
177 marks.append(["alignment_required", "N"])
178
179 markings=""
180 for mark in marks:
181 if zone.__getattr__(mark[0]) :
182 markings+=mark[1]
183 else:
184 markings+=" "
185 out_string += format_string.format(zone, zone.cur_size, zone.page_count,
186 zone.count, free_elements, free_size,
187 zone.elem_size, zone.alloc_size, alloc_count,
3e170ce0 188 alloc_pages, alloc_waste, name = zone.zone_name, markings=markings)
39236c6e
A
189
190 if zone.exhaustible :
191 out_string += "(max: {:d})".format(zone.max_size)
192
193 return out_string
194
195@lldb_command('zprint')
196def Zprint(cmd_args=None):
197 """ Routine to print a summary listing of all the kernel zones
198 All columns are printed in decimal
199 Legend:
200 C - collectable
201 X - expandable
202 $ - not encrypted during hibernation
203 @ - allocs and frees are accounted to caller process for KPRVT
204 H - exhaustible
205 F - allows foreign memory (memory not allocated from zone_map)
206 M - gzalloc will avoid monitoring this zone
207 R - will be refilled when below low water mark
208 O - does not allow refill callout to fill zone on noblock allocation
209 N - zone requires alignment (avoids padding this zone for debugging)
3e170ce0
A
210 A - currently trying to allocate more backing memory from kernel_memory_allocate without VM priv
211 S - currently trying to allocate more backing memory from kernel_memory_allocate with VM priv
39236c6e
A
212 W - another thread is waiting for more memory
213 L - zone is being monitored by zleaks
214 G - currently running GC
3e170ce0 215 P - uses zone_page_metadata
39236c6e
A
216 """
217 global kern
218 print GetZoneSummary.header
219 for zval in kern.zones:
220 print GetZoneSummary(zval)
221
222@xnudebug_test('test_zprint')
223def TestZprint(kernel_target, config, lldb_obj, isConnected ):
224 """ Test the functionality of zprint command
225 returns
226 - False on failure
227 - True on success
228 """
229 if not isConnected:
230 print "Target is not connected. Cannot test memstats"
231 return False
232 res = lldb.SBCommandReturnObject()
233 lldb_obj.debugger.GetCommandInterpreter().HandleCommand("zprint", res)
234 result = res.GetOutput()
235 if len(result.split("\n")) > 2:
236 return True
237 else:
238 return False
239
240
241# EndMacro: zprint
242
243# Macro: showzfreelist
244
245def ShowZfreeListHeader(zone):
246 """ Helper routine to print a header for zone freelist.
247 (Since the freelist does not have a custom type, this is not defined as a Type Summary).
248 params:
249 zone:zone_t - Zone object to print header info
250 returns:
251 None
252 """
fe8ab488
A
253
254 scaled_factor = (unsigned(kern.globals.zp_factor) +
255 (unsigned(zone.elem_size) >> unsigned(kern.globals.zp_scale)))
256
39236c6e
A
257 out_str = ""
258 out_str += "{0: <9s} {1: <12s} {2: <18s} {3: <18s} {4: <6s}\n".format('ELEM_SIZE', 'COUNT', 'NCOOKIE', 'PCOOKIE', 'FACTOR')
259 out_str += "{0: <9d} {1: <12d} 0x{2:0>16x} 0x{3:0>16x} {4: <2d}/{5: <2d}\n\n".format(
fe8ab488 260 zone.elem_size, zone.count, kern.globals.zp_nopoison_cookie, kern.globals.zp_poisoned_cookie, zone.zp_count, scaled_factor)
39236c6e
A
261 out_str += "{0: <7s} {1: <18s} {2: <18s} {3: <18s} {4: <18s} {5: <18s} {6: <14s}\n".format(
262 'NUM', 'ELEM', 'NEXT', 'BACKUP', '^ NCOOKIE', '^ PCOOKIE', 'POISON (PREV)')
263 print out_str
264
265def ShowZfreeListChain(zone, zfirst, zlimit):
266 """ Helper routine to print a zone free list chain
267 params:
268 zone: zone_t - Zone object
269 zfirst: void * - A pointer to the first element of the free list chain
270 zlimit: int - Limit for the number of elements to be printed by showzfreelist
271 returns:
272 None
273 """
274 current = Cast(zfirst, 'void *')
275 while ShowZfreeList.elts_found < zlimit:
276 ShowZfreeList.elts_found += 1
277 znext = dereference(Cast(current, 'vm_offset_t *'))
278 backup_ptr = kern.GetValueFromAddress((unsigned(Cast(current, 'vm_offset_t')) + unsigned(zone.elem_size) - sizeof('vm_offset_t')), 'vm_offset_t *')
279 backup_val = dereference(backup_ptr)
280 n_unobfuscated = (unsigned(backup_val) ^ unsigned(kern.globals.zp_nopoison_cookie))
281 p_unobfuscated = (unsigned(backup_val) ^ unsigned(kern.globals.zp_poisoned_cookie))
282 poison_str = ''
283 if p_unobfuscated == unsigned(znext):
284 poison_str = "P ({0: <d})".format(ShowZfreeList.elts_found - ShowZfreeList.last_poisoned)
285 ShowZfreeList.last_poisoned = ShowZfreeList.elts_found
286 else:
287 if n_unobfuscated != unsigned(znext):
288 poison_str = "INVALID"
289 print "{0: <7d} 0x{1:0>16x} 0x{2:0>16x} 0x{3:0>16x} 0x{4:0>16x} 0x{5:0>16x} {6: <14s}\n".format(
290 ShowZfreeList.elts_found, unsigned(current), unsigned(znext), unsigned(backup_val), n_unobfuscated, p_unobfuscated, poison_str)
291 if unsigned(znext) == 0:
292 break
293 current = Cast(znext, 'void *')
294
295@static_var('elts_found',0)
296@static_var('last_poisoned',0)
297@lldb_command('showzfreelist')
298def ShowZfreeList(cmd_args=None):
299 """ Walk the freelist for a zone, printing out the primary and backup next pointers, the poisoning cookies, and the poisoning status of each element.
300 Usage: showzfreelist <zone> [iterations]
301
302 Will walk up to 50 elements by default, pass a limit in 'iterations' to override.
303 """
304 if not cmd_args:
305 print ShowZfreeList.__doc__
306 return
307 ShowZfreeList.elts_found = 0
308 ShowZfreeList.last_poisoned = 0
309
310 zone = kern.GetValueFromAddress(cmd_args[0], 'struct zone *')
311 zlimit = 50
312 if len(cmd_args) >= 2:
313 zlimit = ArgumentStringToInt(cmd_args[1])
314 ShowZfreeListHeader(zone)
315
316 if unsigned(zone.use_page_list) == 1:
317 if unsigned(zone.allows_foreign) == 1:
318 for free_page_meta in IterateQueue(zone.pages.any_free_foreign, 'struct zone_page_metadata *', 'pages'):
319 if ShowZfreeList.elts_found == zlimit:
320 break
321 zfirst = Cast(free_page_meta.elements, 'void *')
322 if unsigned(zfirst) != 0:
323 ShowZfreeListChain(zone, zfirst, zlimit)
324 for free_page_meta in IterateQueue(zone.pages.intermediate, 'struct zone_page_metadata *', 'pages'):
325 if ShowZfreeList.elts_found == zlimit:
326 break
327 zfirst = Cast(free_page_meta.elements, 'void *')
328 if unsigned(zfirst) != 0:
329 ShowZfreeListChain(zone, zfirst, zlimit)
330 for free_page_meta in IterateQueue(zone.pages.all_free, 'struct zone_page_metadata *', 'pages'):
331 if ShowZfreeList.elts_found == zlimit:
332 break
333 zfirst = Cast(free_page_meta.elements, 'void *')
334 if unsigned(zfirst) != 0:
335 ShowZfreeListChain(zone, zfirst, zlimit)
336 else:
337 zfirst = Cast(zone.free_elements, 'void *')
338 if unsigned(zfirst) != 0:
339 ShowZfreeListChain(zone, zfirst, zlimit)
340
341 if ShowZfreeList.elts_found == zlimit:
342 print "Stopped at {0: <d} elements!".format(zlimit)
343 else:
344 print "Found {0: <d} elements!".format(ShowZfreeList.elts_found)
345
346# EndMacro: showzfreelist
347
348# Macro: zstack
349
350@lldb_command('zstack')
351def Zstack(cmd_args=None):
352 """ Zone leak debugging: Print the stack trace of log element at <index>. If a <count> is supplied, it prints <count> log elements starting at <index>.
353 Usage: zstack <index> [<count>]
354
355 The suggested usage is to look at indexes below zcurrent and look for common stack traces.
356 The stack trace that occurs the most is probably the cause of the leak. Find the pc of the
357 function calling into zalloc and use the countpcs command to find out how often that pc occurs in the log.
358 The pc occuring in a high percentage of records is most likely the source of the leak.
359
360 The findoldest command is also useful for leak debugging since it identifies the oldest record
361 in the log, which may indicate the leaker.
362 """
363 if not cmd_args:
364 print Zstack.__doc__
365 return
366 if int(kern.globals.log_records) == 0:
367 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
368 return
369 if int(kern.globals.zlog_btlog) == 0:
370 print "Zone logging enabled, but zone has not been initialized yet."
371 return
372
373 count = 1
374 if len(cmd_args) >= 2:
375 count = ArgumentStringToInt(cmd_args[1])
376 zstack_index = unsigned(cmd_args[0])
377 while count and (zstack_index != 0xffffff):
378 zstack_record_offset = zstack_index * unsigned(kern.globals.zlog_btlog.btrecord_size)
379 zstack_record = kern.GetValueFromAddress(unsigned(kern.globals.zlog_btlog.btrecords) + zstack_record_offset, 'btlog_record_t *')
380 ShowZStackRecord(zstack_record, zstack_index)
381 zstack_index = zstack_record.next
382 count -= 1
383
384# EndMacro : zstack
385
386# Macro: findoldest
387
388@lldb_command('findoldest')
389def FindOldest(cmd_args=None):
390 """ Zone leak debugging: find and print the oldest record in the log.
391
392 Once it prints a stack trace, find the pc of the caller above all the zalloc, kalloc and
393 IOKit layers. Then use the countpcs command to see how often this caller has allocated
394 memory. A caller with a high percentage of records in the log is probably the leaker.
395 """
396 if int(kern.globals.log_records) == 0:
397 print FindOldest.__doc__
398 return
399 if int(kern.globals.zlog_btlog) == 0:
400 print "Zone logging enabled, but zone has not been initialized yet."
401 return
402 index = kern.globals.zlog_btlog.head
403 if unsigned(index) != 0xffffff:
404 print "Oldest record is at log index: {0: <d}".format(index)
405 Zstack([index])
406 else:
407 print "No Records Present"
408
409# EndMacro : findoldest
410
411# Macro: countpcs
412
413@lldb_command('countpcs')
414def Countpcs(cmd_args=None):
415 """ Zone leak debugging: search the log and print a count of all log entries that contain the given <pc>
416 in the stack trace.
417 Usage: countpcs <pc>
418
419 This is useful for verifying a suspected <pc> as being the source of
420 the leak. If a high percentage of the log entries contain the given <pc>, then it's most
421 likely the source of the leak. Note that this command can take several minutes to run.
422 """
423 if not cmd_args:
424 print Countpcs.__doc__
425 return
426 if int(kern.globals.log_records) == 0:
427 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
428 return
429 if int(kern.globals.zlog_btlog) == 0:
430 print "Zone logging enabled, but zone has not been initialized yet."
431 return
432
433 cpcs_index = unsigned(kern.globals.zlog_btlog.head)
434 target_pc = unsigned(kern.GetValueFromAddress(cmd_args[0], 'void *'))
435 found = 0
436 depth = unsigned(kern.globals.zlog_btlog.btrecord_btdepth)
437
438 while cpcs_index != 0xffffff:
439 cpcs_record_offset = cpcs_index * unsigned(kern.globals.zlog_btlog.btrecord_size)
440 cpcs_record = kern.GetValueFromAddress(unsigned(kern.globals.zlog_btlog.btrecords) + cpcs_record_offset, 'btlog_record_t *')
441 frame = 0
442 while frame < depth:
443 frame_pc = unsigned(cpcs_record.bt[frame])
444 if frame_pc == target_pc:
445 found += 1
446 break
447 frame += 1
448 cpcs_index = cpcs_record.next
449 print "Occured {0: <d} times in log ({1: <d}{2: <s} of records)".format(found, (found * 100)/unsigned(kern.globals.zlog_btlog.activecount), '%')
450
451# EndMacro: countpcs
452
453# Macro: findelem
454
455@lldb_command('findelem')
456def FindElem(cmd_args=None):
457 """ Zone corruption debugging: search the log and print out the stack traces for all log entries that
458 refer to the given zone element.
459 Usage: findelem <elem addr>
460
461 When the kernel panics due to a corrupted zone element, get the
462 element address and use this command. This will show you the stack traces of all logged zalloc and
463 zfree operations which tells you who touched the element in the recent past. This also makes
464 double-frees readily apparent.
465 """
466 if not cmd_args:
467 print FindElem.__doc__
468 return
469 if int(kern.globals.log_records) == 0:
470 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
471 return
472 if int(kern.globals.zlog_btlog) == 0:
473 print "Zone logging enabled, but zone has not been initialized yet."
474 return
475
476 target_element = unsigned(kern.GetValueFromAddress(cmd_args[0], 'void *'))
477 index = unsigned(kern.globals.zlog_btlog.head)
478 prev_op = -1
479
480 while index != 0xffffff:
481 findelem_record_offset = index * unsigned(kern.globals.zlog_btlog.btrecord_size)
482 findelem_record = kern.GetValueFromAddress(unsigned(kern.globals.zlog_btlog.btrecords) + findelem_record_offset, 'btlog_record_t *')
483 if unsigned(findelem_record.element) == target_element:
484 Zstack([index])
485 if int(findelem_record.operation) == prev_op:
486 print "{0: <s} DOUBLE OP! {1: <s}".format(('*' * 8), ('*' * 8))
487 prev_op = int(findelem_record.operation)
488 index = findelem_record.next
489
490# EndMacro: findelem
491
492# Macro: btlog_find
493
fe8ab488 494@lldb_command('btlog_find', "AS")
39236c6e
A
495def BtlogFind(cmd_args=None, cmd_options={}):
496 """ Search the btlog_t for entries corresponding to the given element.
497 Use -A flag to print all entries.
fe8ab488 498 Use -S flag to summarize the count of records
39236c6e
A
499 Usage: btlog_find <btlog_t> <element>
500 Usage: btlog_find <btlog_t> -A
501 Note: Backtraces will be in chronological order, with oldest entries aged out in FIFO order as needed.
502 """
503 if not cmd_args:
504 raise ArgumentError("Need a btlog_t parameter")
505 btlog = kern.GetValueFromAddress(cmd_args[0], 'btlog_t *')
506 printall = False
fe8ab488
A
507 summarize = False
508 summary_cache = {}
509 target_elem = 0xffffffff
39236c6e
A
510
511 if "-A" in cmd_options:
512 printall = True
513 else:
514 if not printall and len(cmd_args) < 2:
515 raise ArgumentError("<element> is missing in args. Need a search pointer.")
516 target_elem = unsigned(kern.GetValueFromAddress(cmd_args[1], 'void *'))
517
fe8ab488
A
518 if "-S" in cmd_options:
519 summarize = True
520
39236c6e
A
521 index = unsigned(btlog.head)
522 progress = 0
523 record_size = unsigned(btlog.btrecord_size)
fe8ab488
A
524 try:
525 while index != 0xffffff:
526 record_offset = index * record_size
527 record = kern.GetValueFromAddress(unsigned(btlog.btrecords) + record_offset, 'btlog_record_t *')
528 if printall or unsigned(record.element) == target_elem:
529 _s = '{0: <s} {2: <#0x} OP {1: <d} {3: <s}'.format(('-' * 8), record.operation, unsigned(record.element), ('-' * 8))
530 _s += GetBtlogBacktrace(btlog.btrecord_btdepth, record)
531 if summarize:
532 if _s not in summary_cache:
533 summary_cache[_s] = 1
534 else:
535 summary_cache[_s] += 1
536 else :
537 print _s
538 index = record.next
539 progress += 1
540 if (progress % 1000) == 0: print '{0: <d} entries searched!\n'.format(progress)
541 except ValueError, e:
542 pass
543
544 if summarize:
545 print "=================== SUMMARY =================="
546 for (k,v) in summary_cache.iteritems():
547 print "Count: %d %s \n " % (v, k)
548 return
39236c6e
A
549
550#EndMacro: btlog_find
551
552#Macro: showzalloc
553
554@lldb_command('showzalloc')
555def ShowZalloc(cmd_args=None):
556 """ Prints a zallocation from the zallocations array based off its index and prints the associated symbolicated backtrace.
557 Usage: showzalloc <index>
558 """
559 if not cmd_args:
560 print ShowZalloc.__doc__
561 return
562 if unsigned(kern.globals.zallocations) == 0:
563 print "zallocations array not initialized!"
564 return
565 zallocation = kern.globals.zallocations[ArgumentStringToInt(cmd_args[0])]
566 print zallocation
567 ShowZTrace([str(int(zallocation.za_trace_index))])
568
569#EndMacro: showzalloc
570
571#Macro: showztrace
572
573@lldb_command('showztrace')
574def ShowZTrace(cmd_args=None):
575 """ Prints the backtrace from the ztraces array at index
576 Usage: showztrace <trace index>
577 """
578 if not cmd_args:
579 print ShowZTrace.__doc__
580 return
581 if unsigned(kern.globals.ztraces) == 0:
582 print "ztraces array not initialized!"
583 return
584 ztrace_addr = kern.globals.ztraces[ArgumentStringToInt(cmd_args[0])]
585 print ztrace_addr
586 ShowZstackTraceHelper(ztrace_addr.zt_stack, ztrace_addr.zt_depth)
587
588#EndMacro: showztrace
589
590#Macro: showztraceaddr
591
592@lldb_command('showztraceaddr')
593def ShowZTraceAddr(cmd_args=None):
594 """ Prints the struct ztrace passed in.
595 Usage: showztraceaddr <trace address>
596 """
597 if not cmd_args:
598 print ShowZTraceAddr.__doc__
599 return
600 ztrace_ptr = kern.GetValueFromAddress(cmd_args[0], 'struct ztrace *')
601 print dereference(ztrace_ptr)
602 ShowZstackTraceHelper(ztrace_ptr.zt_stack, ztrace_ptr.zt_depth)
603
604#EndMacro: showztraceaddr
605
606#Macro: showzstacktrace
607
608@lldb_command('showzstacktrace')
609def ShowZstackTrace(cmd_args=None):
610 """ Routine to print a stacktrace stored by OSBacktrace.
611 Usage: showzstacktrace <saved stacktrace> [size]
612
613 size is optional, defaults to 15.
614 """
615 if not cmd_args:
616 print ShowZstackTrace.__doc__
617 return
618 void_ptr_type = gettype('void *')
619 void_double_ptr_type = void_ptr_type.GetPointerType()
620 trace = kern.GetValueFromAddress(cmd_args[0], void_double_ptr_type)
621 trace_size = 15
622 if len(cmd_args) >= 2:
623 trace_size = ArgumentStringToInt(cmd_args[1])
624 ShowZstackTraceHelper(trace, trace_size)
625
626#EndMacro: showzstacktrace
627
628def ShowZstackTraceHelper(stack, depth):
629 """ Helper routine for printing a zstack.
630 params:
631 stack: void *[] - An array of pointers representing the Zstack
632 depth: int - The depth of the ztrace stack
633 returns:
634 None
635 """
636 trace_current = 0
637 while trace_current < depth:
638 trace_addr = stack[trace_current]
639 symbol_arr = kern.SymbolicateFromAddress(unsigned(trace_addr))
640 if symbol_arr:
641 symbol_str = str(symbol_arr[0].addr)
642 else:
643 symbol_str = ''
644 print '{0: <#x} {1: <s}'.format(trace_addr, symbol_str)
645 trace_current += 1
646
647#Macro: showtopztrace
648
649@lldb_command('showtopztrace')
650def ShowTopZtrace(cmd_args=None):
651 """ Shows the ztrace with the biggest size.
652 (According to top_ztrace, not by iterating through the hash table)
653 """
654 top_trace = kern.globals.top_ztrace
655 print 'Index: {0: <d}'.format((unsigned(top_trace) - unsigned(kern.globals.ztraces)) / sizeof('struct ztrace'))
656 print dereference(top_trace)
657 ShowZstackTraceHelper(top_trace.zt_stack, top_trace.zt_depth)
658
659#EndMacro: showtopztrace
660
661#Macro: showzallocs
662
663@lldb_command('showzallocs')
664def ShowZallocs(cmd_args=None):
665 """ Prints all allocations in the zallocations table
666 """
667 if unsigned(kern.globals.zallocations) == 0:
668 print "zallocations array not initialized!"
669 return
670 print '{0: <5s} {1: <18s} {2: <5s} {3: <15s}'.format('INDEX','ADDRESS','TRACE','SIZE')
671 current_index = 0
672 max_zallocation = unsigned(kern.globals.zleak_alloc_buckets)
673 allocation_count = 0
674 while current_index < max_zallocation:
675 current_zalloc = kern.globals.zallocations[current_index]
676 if int(current_zalloc.za_element) != 0:
677 print '{0: <5d} {1: <#018x} {2: <5d} {3: <15d}'.format(current_index, current_zalloc.za_element, current_zalloc.za_trace_index, unsigned(current_zalloc.za_size))
678 allocation_count += 1
679 current_index += 1
680 print 'Total Allocations: {0: <d}'.format(allocation_count)
681
682#EndMacro: showzallocs
683
684#Macro: showzallocsfortrace
685
686@lldb_command('showzallocsfortrace')
687def ShowZallocsForTrace(cmd_args=None):
688 """ Prints all allocations pointing to the passed in trace's index into ztraces by looking through zallocations table
689 Usage: showzallocsfortrace <trace index>
690 """
691 if not cmd_args:
692 print ShowZallocsForTrace.__doc__
693 return
694 print '{0: <5s} {1: <18s} {2: <15s}'.format('INDEX','ADDRESS','SIZE')
695 target_index = ArgumentStringToInt(cmd_args[0])
696 current_index = 0
697 max_zallocation = unsigned(kern.globals.zleak_alloc_buckets)
698 allocation_count = 0
699 while current_index < max_zallocation:
700 current_zalloc = kern.globals.zallocations[current_index]
701 if unsigned(current_zalloc.za_element) != 0 and (unsigned(current_zalloc.za_trace_index) == unsigned(target_index)):
702 print '{0: <5d} {1: <#018x} {2: <6d}'.format(current_index, current_zalloc.za_element, current_zalloc.za_size)
703 allocation_count += 1
704 current_index += 1
705 print 'Total Allocations: {0: <d}'.format(allocation_count)
706
707#EndMacro: showzallocsfortrace
708
709#Macro: showztraces
710
711@lldb_command('showztraces')
712def ShowZTraces(cmd_args=None):
713 """ Prints all traces with size > 0
714 """
715 ShowZTracesAbove([0])
716
717#EndMacro: showztraces
718
719#Macro: showztracesabove
720
721@lldb_command('showztracesabove')
722def ShowZTracesAbove(cmd_args=None):
723 """ Prints all traces with size greater than X
724 Usage: showztracesabove <size>
725 """
726 if not cmd_args:
727 print ShowZTracesAbove.__doc__
728 return
729 print '{0: <5s} {1: <6s}'.format('INDEX','SIZE')
730 current_index = 0
731 ztrace_count = 0
732 max_ztrace = unsigned(kern.globals.zleak_trace_buckets)
733 while current_index < max_ztrace:
734 ztrace_current = kern.globals.ztraces[current_index]
735 if ztrace_current.zt_size > unsigned(cmd_args[0]):
736 print '{0: <5d} {1: <6d}'.format(current_index, int(ztrace_current.zt_size))
737 ztrace_count += 1
738 current_index += 1
739 print 'Total traces: {0: <d}'.format(ztrace_count)
740
741#EndMacro: showztracesabove
742
743#Macro: showztracehistogram
744
745@lldb_command('showztracehistogram')
746def ShowZtraceHistogram(cmd_args=None):
747 """ Prints the histogram of the ztrace table
748 """
749 print '{0: <5s} {1: <9s} {2: <10s}'.format('INDEX','HIT_COUNT','COLLISIONS')
750 current_index = 0
751 ztrace_count = 0
752 max_ztrace = unsigned(kern.globals.zleak_trace_buckets)
753 while current_index < max_ztrace:
754 ztrace_current = kern.globals.ztraces[current_index]
755 if ztrace_current.zt_hit_count != 0:
756 print '{0: <5d} {1: <9d} {2: <10d}'.format(current_index, ztrace_current.zt_hit_count, ztrace_current.zt_collisions)
757 ztrace_count += 1
758 current_index += 1
759 print 'Total traces: {0: <d}'.format(ztrace_count)
760
761#EndMacro: showztracehistogram
762
763#Macro: showzallochistogram
764
765@lldb_command('showzallochistogram')
766def ShowZallocHistogram(cmd_args=None):
767 """ Prints the histogram for the zalloc table
768 """
769 print '{0: <5s} {1: <9s}'.format('INDEX','HIT_COUNT')
770 current_index = 0
771 zallocation_count = 0
772 max_ztrace = unsigned(kern.globals.zleak_alloc_buckets)
773 while current_index < max_ztrace:
774 zallocation_current = kern.globals.zallocations[current_index]
775 if zallocation_current.za_hit_count != 0:
776 print '{0: <5d} {1: <9d}'.format(current_index, zallocation_current.za_hit_count)
777 zallocation_count += 1
778 current_index += 1
779 print 'Total Allocations: {0: <d}'.format(zallocation_count)
780
781#EndMacro: showzallochistogram
782
783#Macro: showzstats
784
785@lldb_command('showzstats')
786def ShowZstats(cmd_args=None):
787 """ Prints the zone leak detection stats
788 """
789 print 'z_alloc_collisions: {0: <d}, z_trace_collisions: {1: <d}'.format(unsigned(kern.globals.z_alloc_collisions), unsigned(kern.globals.z_trace_collisions))
790 print 'z_alloc_overwrites: {0: <d}, z_trace_overwrites: {1: <d}'.format(unsigned(kern.globals.z_alloc_overwrites), unsigned(kern.globals.z_trace_overwrites))
791 print 'z_alloc_recorded: {0: <d}, z_trace_recorded: {1: <d}'.format(unsigned(kern.globals.z_alloc_recorded), unsigned(kern.globals.z_trace_recorded))
792
793#EndMacro: showzstats
794
fe8ab488
A
795def GetBtlogBacktrace(depth, zstack_record):
796 """ Helper routine for getting a BT Log record backtrace stack.
39236c6e
A
797 params:
798 depth:int - The depth of the zstack record
799 zstack_record:btlog_record_t * - A BTLog record
800 returns:
fe8ab488 801 str - string with backtrace in it.
39236c6e
A
802 """
803 out_str = ''
804 frame = 0
805 if not zstack_record:
fe8ab488
A
806 return "Zstack record none!"
807
39236c6e
A
808 depth_val = unsigned(depth)
809 while frame < depth_val:
810 frame_pc = zstack_record.bt[frame]
811 if not frame_pc or int(frame_pc) == 0:
812 break
813 symbol_arr = kern.SymbolicateFromAddress(frame_pc)
814 if symbol_arr:
815 symbol_str = str(symbol_arr[0].addr)
816 else:
817 symbol_str = ''
818 out_str += "{0: <#0x} <{1: <s}>\n".format(frame_pc, symbol_str)
819 frame += 1
fe8ab488 820 return out_str
39236c6e
A
821
822def ShowZStackRecord(zstack_record, zstack_index):
823 """ Helper routine for printing a single zstack record
824 params:
825 zstack_record:btlog_record_t * - A BTLog record
826 zstack_index:int - Index for the record in the BTLog table
827 returns:
828 None
829 """
830 out_str = ('-' * 8)
831 if zstack_record.operation == 1:
832 out_str += "ALLOC "
833 else:
834 out_str += "FREE "
835 out_str += "{0: <#0x} : Index {1: <d} {2: <s}\n".format(zstack_record.element, zstack_index, ('-' * 8))
836 print out_str
fe8ab488 837 print GetBtlogBacktrace(kern.globals.zlog_btlog.btrecord_btdepth, zstack_record)
39236c6e
A
838
839# Macro: showioalloc
840
841@lldb_command('showioalloc')
842def ShowIOAllocations(cmd_args=None):
843 """ Show some accounting of memory allocated by IOKit allocators. See ioalloccount man page for details.
844 Routine to display a summary of memory accounting allocated by IOKit allocators.
845 """
846 print "Instance allocation = {0: <#0x} = {1: d}K".format(kern.globals.debug_ivars_size, (kern.globals.debug_ivars_size / 1024))
847 print "Container allocation = {0: <#0x} = {1: d}K".format(kern.globals.debug_container_malloc_size, (kern.globals.debug_container_malloc_size / 1024))
848 print "IOMalloc allocation = {0: <#0x} = {1: d}K".format(kern.globals.debug_iomalloc_size, (kern.globals.debug_iomalloc_size / 1024))
849 print "Container allocation = {0: <#0x} = {1: d}K".format(kern.globals.debug_iomallocpageable_size, (kern.globals.debug_iomallocpageable_size / 1024))
850
851
852# EndMacro: showioalloc
853
854
3e170ce0
A
855# Macro: showselectmem
856@lldb_command('showselectmem', "S:")
857def ShowSelectMem(cmd_args=None, cmd_options={}):
858 """ Show memory cached by threads on calls to select.
859
860 usage: showselectmem [-v]
861 -v : print each thread's memory
862 (one line per thread with non-zero select memory)
863 -S {addr} : Find the thread whose thread-local select set
864 matches the given address
865 """
866 verbose = False
867 opt_wqs = 0
868 if config['verbosity'] > vHUMAN:
869 verbose = True
870 if "-S" in cmd_options:
871 opt_wqs = unsigned(kern.GetValueFromAddress(cmd_options["-S"], 'uint64_t *'))
872 if opt_wqs == 0:
873 raise ArgumentError("Invalid waitq set address: {:s}".format(cmd_options["-S"]))
874 selmem = 0
875 if verbose:
876 print "{:18s} {:10s} {:s}".format('Task', 'Thread ID', 'Select Mem (bytes)')
877 for t in kern.tasks:
878 for th in IterateQueue(t.threads, 'thread *', 'task_threads'):
879 uth = Cast(th.uthread, 'uthread *');
880 wqs = 0
881 if hasattr(uth, 'uu_allocsize'): # old style
882 thmem = uth.uu_allocsize
883 wqs = uth.uu_wqset
884 elif hasattr(uth, 'uu_wqstate_sz'): # new style
885 thmem = uth.uu_wqstate_sz
886 wqs = uth.uu_wqset
887 else:
888 print "What kind of uthread is this?!"
889 return
890 if opt_wqs and opt_wqs == unsigned(wqs):
891 print "FOUND: {:#x} in thread: {:#x} ({:#x})".format(opt_wqs, unsigned(th), unsigned(th.thread_id))
892 if verbose and thmem > 0:
893 print "{:<#18x} {:<#10x} {:d}".format(unsigned(t), unsigned(th.thread_id), thmem)
894 selmem += thmem
895 print '-'*40
896 print "Total: {:d} bytes ({:d} kbytes)".format(selmem, selmem/1024)
897# Endmacro: showselectmem
39236c6e
A
898
899
900# Macro: showtaskvme
fe8ab488
A
901@lldb_command('showtaskvme', "PS")
902def ShowTaskVmeHelper(cmd_args=None, cmd_options={}):
39236c6e
A
903 """ Display a summary list of the specified vm_map's entries
904 Usage: showtaskvme <task address> (ex. showtaskvme 0x00ataskptr00 )
3e170ce0
A
905 Use -S flag to show VM object shadow chains
906 Use -P flag to show pager info (mapped file, compressed pages, ...)
39236c6e 907 """
fe8ab488
A
908 show_pager_info = False
909 show_all_shadows = False
910 if "-P" in cmd_options:
911 show_pager_info = True
912 if "-S" in cmd_options:
913 show_all_shadows = True
39236c6e 914 task = kern.GetValueFromAddress(cmd_args[0], 'task *')
fe8ab488 915 ShowTaskVMEntries(task, show_pager_info, show_all_shadows)
39236c6e 916
fe8ab488
A
917@lldb_command('showallvme', "PS")
918def ShowAllVME(cmd_args=None, cmd_options={}):
39236c6e 919 """ Routine to print a summary listing of all the vm map entries
fe8ab488
A
920 Go Through each task in system and show the vm memory regions
921 Use -S flag to show VM object shadow chains
922 Use -P flag to show pager info (mapped file, compressed pages, ...)
923 """
924 show_pager_info = False
925 show_all_shadows = False
926 if "-P" in cmd_options:
927 show_pager_info = True
928 if "-S" in cmd_options:
929 show_all_shadows = True
39236c6e 930 for task in kern.tasks:
fe8ab488 931 ShowTaskVMEntries(task, show_pager_info, show_all_shadows)
39236c6e
A
932
933@lldb_command('showallvm')
934def ShowAllVM(cmd_args=None):
935 """ Routine to print a summary listing of all the vm maps
936 """
937 for task in kern.tasks:
938 print GetTaskSummary.header + ' ' + GetProcSummary.header
939 print GetTaskSummary(task) + ' ' + GetProcSummary(Cast(task.bsd_info, 'proc *'))
940 print GetVMMapSummary.header
941 print GetVMMapSummary(task.map)
942
943@lldb_command("showtaskvm")
944def ShowTaskVM(cmd_args=None):
945 """ Display info about the specified task's vm_map
946 syntax: (lldb) showtaskvm <task_ptr>
947 """
948 if not cmd_args:
949 print ShowTaskVM.__doc__
950 return False
951 task = kern.GetValueFromAddress(cmd_args[0], 'task *')
952 if not task:
953 print "Unknown arguments."
954 return False
955 print GetTaskSummary.header + ' ' + GetProcSummary.header
956 print GetTaskSummary(task) + ' ' + GetProcSummary(Cast(task.bsd_info, 'proc *'))
957 print GetVMMapSummary.header
958 print GetVMMapSummary(task.map)
959 return True
960
961@lldb_command('showallvmstats')
962def ShowAllVMStats(cmd_args=None):
963 """ Print a summary of vm statistics in a table format
964 """
3e170ce0 965 page_size = kern.globals.page_size
39236c6e
A
966 vmstats = lambda:None
967 vmstats.wired_count = 0
968 vmstats.resident_count = 0
969 vmstats.resident_max = 0
970 vmstats.internal = 0
971 vmstats.external = 0
972 vmstats.reusable = 0
973 vmstats.compressed = 0
974 vmstats.compressed_peak = 0
975 vmstats.compressed_lifetime = 0
976 vmstats.error = ''
977
978 hdr_format = "{0: >10s} {1: <20s} {2: >6s} {3: >10s} {4: >10s} {5: >10s} {6: >10s} {7: >10s} {8: >10s} {9: >10s} {10: >10s} {11: >10s} {12: >10s} {13: >10s} {14:}"
979 print hdr_format.format('pid', 'command', '#ents', 'wired', 'vsize', 'rsize', 'NEW RSIZE', 'max rsize', 'internal', 'external', 'reusable', 'compressed', 'compressed', 'compressed', '')
980 print hdr_format.format('', '', '', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(current)', '(peak)', '(lifetime)', '')
981 entry_format = "{p.p_pid: >10d} {p.p_comm: <20s} {m.hdr.nentries: >6d} {s.wired_count: >10d} {vsize: >10d} {s.resident_count: >10d} {s.new_resident_count: >10d} {s.resident_max: >10d} {s.internal: >10d} {s.external: >10d} {s.reusable: >10d} {s.compressed: >10d} {s.compressed_peak: >10d} {s.compressed_lifetime: >10d} {s.error}"
982
983 for task in kern.tasks:
984 proc = Cast(task.bsd_info, 'proc *')
985 vmmap = Cast(task.map, '_vm_map *')
986 vmstats.error = ''
987 vmstats.wired_count = vmmap.pmap.stats.wired_count;
988 vmstats.resident_count = unsigned(vmmap.pmap.stats.resident_count);
989 vmstats.resident_max = vmmap.pmap.stats.resident_max;
990 vmstats.internal = unsigned(vmmap.pmap.stats.internal);
991 vmstats.external = unsigned(vmmap.pmap.stats.external);
992 vmstats.reusable = unsigned(vmmap.pmap.stats.reusable);
993 vmstats.compressed = unsigned(vmmap.pmap.stats.compressed);
994 vmstats.compressed_peak = unsigned(vmmap.pmap.stats.compressed_peak);
995 vmstats.compressed_lifetime = unsigned(vmmap.pmap.stats.compressed_lifetime);
996 vmstats.new_resident_count = vmstats.internal + vmstats.external
997
998 if vmstats.internal < 0:
999 vmstats.error += '*'
1000 if vmstats.external < 0:
1001 vmstats.error += '*'
1002 if vmstats.reusable < 0:
1003 vmstats.error += '*'
1004 if vmstats.compressed < 0:
1005 vmstats.error += '*'
1006 if vmstats.compressed_peak < 0:
1007 vmstats.error += '*'
1008 if vmstats.compressed_lifetime < 0:
1009 vmstats.error += '*'
1010 if vmstats.new_resident_count +vmstats.reusable != vmstats.resident_count:
1011 vmstats.error += '*'
1012
3e170ce0 1013 print entry_format.format(p=proc, m=vmmap, vsize=(unsigned(vmmap.size) / page_size), t=task, s=vmstats)
39236c6e
A
1014
1015
fe8ab488 1016def ShowTaskVMEntries(task, show_pager_info, show_all_shadows):
39236c6e
A
1017 """ Routine to print out a summary listing of all the entries in a vm_map
1018 params:
1019 task - core.value : a object of type 'task *'
1020 returns:
1021 None
1022 """
1023 print "vm_map entries for task " + hex(task)
1024 print GetTaskSummary.header
1025 print GetTaskSummary(task)
1026 if not task.map:
1027 print "Task {0: <#020x} has map = 0x0"
1028 return None
1029 print GetVMMapSummary.header
1030 print GetVMMapSummary(task.map)
1031 vme_list_head = task.map.hdr.links
1032 vme_ptr_type = GetType('vm_map_entry *')
1033 print GetVMEntrySummary.header
1034 for vme in IterateQueue(vme_list_head, vme_ptr_type, "links"):
fe8ab488 1035 print GetVMEntrySummary(vme, show_pager_info, show_all_shadows)
39236c6e
A
1036 return None
1037
1038@lldb_command("showmap")
1039def ShowMap(cmd_args=None):
1040 """ Routine to print out info about the specified vm_map
1041 usage: showmap <vm_map>
1042 """
1043 if cmd_args == None or len(cmd_args) < 1:
1044 print "Invalid argument.", ShowMap.__doc__
1045 return
1046 map_val = kern.GetValueFromAddress(cmd_args[0], 'vm_map_t')
1047 print GetVMMapSummary.header
1048 print GetVMMapSummary(map_val)
1049
1050@lldb_command("showmapvme")
1051def ShowMapVME(cmd_args=None):
1052 """Routine to print out info about the specified vm_map and its vm entries
1053 usage: showmapvme <vm_map>
1054 """
1055 if cmd_args == None or len(cmd_args) < 1:
1056 print "Invalid argument.", ShowMap.__doc__
1057 return
1058 map_val = kern.GetValueFromAddress(cmd_args[0], 'vm_map_t')
1059 print GetVMMapSummary.header
1060 print GetVMMapSummary(map_val)
1061 vme_list_head = map_val.hdr.links
1062 vme_ptr_type = GetType('vm_map_entry *')
1063 print GetVMEntrySummary.header
1064 for vme in IterateQueue(vme_list_head, vme_ptr_type, "links"):
1065 print GetVMEntrySummary(vme)
1066 return None
1067
1068@lldb_type_summary(['_vm_map *', 'vm_map_t'])
1069@header("{0: <20s} {1: <20s} {2: <20s} {3: >5s} {4: >5s} {5: <20s} {6: <20s}".format("vm_map", "pmap", "vm_size", "#ents", "rpage", "hint", "first_free"))
1070def GetVMMapSummary(vmmap):
1071 """ Display interesting bits from vm_map struct """
1072 out_string = ""
1073 format_string = "{0: <#020x} {1: <#020x} {2: <#020x} {3: >5d} {4: >5d} {5: <#020x} {6: <#020x}"
1074 vm_size = uint64_t(vmmap.size).value
1075 resident_pages = 0
1076 if vmmap.pmap != 0: resident_pages = int(vmmap.pmap.stats.resident_count)
1077 out_string += format_string.format(vmmap, vmmap.pmap, vm_size, vmmap.hdr.nentries, resident_pages, vmmap.hint, vmmap.first_free)
1078 return out_string
1079
1080@lldb_type_summary(['vm_map_entry'])
1081@header("{0: <20s} {1: <20s} {2: <5s} {3: >7s} {4: <20s} {5: <20s}".format("entry", "start", "prot", "#page", "object", "offset"))
1082def GetVMEntrySummary(vme):
1083 """ Display vm entry specific information. """
3e170ce0 1084 page_size = kern.globals.page_size
39236c6e
A
1085 out_string = ""
1086 format_string = "{0: <#020x} {1: <#20x} {2: <1x}{3: <1x}{4: <3s} {5: >7d} {6: <#020x} {7: <#020x}"
1087 vme_protection = int(vme.protection)
1088 vme_max_protection = int(vme.max_protection)
1089 vme_extra_info_str ="SC-Ds"[int(vme.inheritance)]
1090 if int(vme.is_sub_map) != 0 :
1091 vme_extra_info_str +="s"
1092 elif int(vme.needs_copy) != 0 :
1093 vme_extra_info_str +="n"
3e170ce0
A
1094 num_pages = (unsigned(vme.links.end) - unsigned(vme.links.start)) / page_size
1095 out_string += format_string.format(vme, vme.links.start, vme_protection, vme_max_protection, vme_extra_info_str, num_pages, vme.vme_object.vmo_object, vme.vme_offset)
39236c6e
A
1096 return out_string
1097
1098# EndMacro: showtaskvme
1099@lldb_command('showmapwired')
1100def ShowMapWired(cmd_args=None):
1101 """ Routine to print out a summary listing of all the entries with wired pages in a vm_map
1102 """
1103 if cmd_args == None or len(cmd_args) < 1:
1104 print "Invalid argument", ShowMapWired.__doc__
1105 return
1106 map_val = kern.GetValueFromAddress(cmd_args[0], 'vm_map_t')
1107
1108
1109@lldb_type_summary(['kmod_info_t *'])
1110@header("{0: <20s} {1: <20s} {2: <20s} {3: >3s} {4: >5s} {5: >20s} {6: <30s}".format('kmod_info', 'address', 'size', 'id', 'refs', 'version', 'name'))
1111def GetKextSummary(kmod):
1112 """ returns a string representation of kext information
1113 """
1114 out_string = ""
1115 format_string = "{0: <#020x} {1: <#020x} {2: <#020x} {3: >3d} {4: >5d} {5: >20s} {6: <30s}"
1116 out_string += format_string.format(kmod, kmod.address, kmod.size, kmod.id, kmod.reference_count, kmod.version, kmod.name)
1117 return out_string
1118
1119@lldb_type_summary(['uuid_t'])
1120@header("")
1121def GetUUIDSummary(uuid):
1122 """ returns a string representation like CA50DA4C-CA10-3246-B8DC-93542489AA26
1123 """
1124 arr = Cast(addressof(uuid), 'uint8_t *')
1125 data = []
1126 for i in range(16):
1127 data.append(int(arr[i]))
1128 return "{a[0]:02X}{a[1]:02X}{a[2]:02X}{a[3]:02X}-{a[4]:02X}{a[5]:02X}-{a[6]:02X}{a[7]:02X}-{a[8]:02X}{a[9]:02X}-{a[10]:02X}{a[11]:02X}{a[12]:02X}{a[13]:02X}{a[14]:02X}{a[15]:02X}".format(a=data)
1129
1130@lldb_command('showallkmods')
1131def ShowAllKexts(cmd_args=None):
1132 """Display a summary listing of all loaded kexts (alias: showallkmods)
1133 """
1134 kmod_val = kern.globals.kmod
1135 print "{: <36s} ".format("UUID") + GetKextSummary.header
1136 kextuuidinfo = GetKextLoadInformation()
1137 for kval in IterateLinkedList(kmod_val, 'next'):
1138 uuid = "........-....-....-....-............"
1139 kaddr = unsigned(kval.address)
1140 for l in kextuuidinfo :
1141 if kaddr == int(l[1],16):
1142 uuid = l[0]
1143 break
1144 print uuid + " " + GetKextSummary(kval)
1145
1146def GetKextLoadInformation(addr=0):
1147 """ Extract the kext uuid and load address information from the kernel data structure.
1148 params:
1149 addr - int - optional integer that is the address to search for.
1150 returns:
1151 [] - array with each entry of format ( 'UUID', 'Hex Load Address')
1152 """
1153 # because of <rdar://problem/12683084>, we can't find summaries directly
1154 #addr = hex(addressof(kern.globals.gLoadedKextSummaries.summaries))
1155 baseaddr = unsigned(kern.globals.gLoadedKextSummaries) + 0x10
1156 summaries_begin = kern.GetValueFromAddress(baseaddr, 'OSKextLoadedKextSummary *')
1157 total_summaries = int(kern.globals.gLoadedKextSummaries.numSummaries)
1158 kext_version = int(kern.globals.gLoadedKextSummaries.version)
1159 entry_size = 64 + 16 + 8 + 8 + 8 + 4 + 4
1160 if kext_version >= 2 :
1161 entry_size = int(kern.globals.gLoadedKextSummaries.entry_size)
1162 retval = []
1163 for i in range(total_summaries):
1164 tmpaddress = unsigned(summaries_begin) + (i * entry_size)
1165 current_kext = kern.GetValueFromAddress(tmpaddress, 'OSKextLoadedKextSummary *')
1166 if addr != 0 :
1167 if addr == unsigned(current_kext.address):
1168 retval.append((GetUUIDSummary(current_kext.uuid) , hex(current_kext.address), str(current_kext.name) ))
1169 else:
1170 retval.append((GetUUIDSummary(current_kext.uuid) , hex(current_kext.address), str(current_kext.name) ))
1171
1172 return retval
1173
1174lldb_alias('showallkexts', 'showallkmods')
1175
1176def GetOSKextVersion(version_num):
1177 """ returns a string of format 1.2.3x from the version_num
1178 params: version_num - int
1179 return: str
1180 """
1181 if version_num == -1 :
1182 return "invalid"
1183 (MAJ_MULT, MIN_MULT, REV_MULT,STAGE_MULT) = (100000000, 1000000, 10000, 1000)
1184 version = version_num
1185
1186 vers_major = version / MAJ_MULT
1187 version = version - (vers_major * MAJ_MULT)
1188
1189 vers_minor = version / MIN_MULT
1190 version = version - (vers_minor * MIN_MULT)
1191
1192 vers_revision = version / REV_MULT
1193 version = version - (vers_revision * REV_MULT)
1194
1195 vers_stage = version / STAGE_MULT
1196 version = version - (vers_stage * STAGE_MULT)
1197
1198 vers_stage_level = version
1199
1200 out_str = "%d.%d" % (vers_major, vers_minor)
1201 if vers_revision > 0: out_str += ".%d" % vers_revision
1202 if vers_stage == 1 : out_str += "d%d" % vers_stage_level
1203 if vers_stage == 3 : out_str += "a%d" % vers_stage_level
1204 if vers_stage == 5 : out_str += "b%d" % vers_stage_level
1205 if vers_stage == 6 : out_str += "fc%d" % vers_stage_level
1206
1207 return out_str
1208
1209@lldb_command('showallknownkmods')
1210def ShowAllKnownKexts(cmd_args=None):
1211 """ Display a summary listing of all kexts known in the system.
1212 This is particularly useful to find if some kext was unloaded before this crash'ed state.
1213 """
1214 kext_count = int(kern.globals.sKextsByID.count)
1215 index = 0
1216 kext_dictionary = kern.globals.sKextsByID.dictionary
1217 print "%d kexts in sKextsByID:" % kext_count
1218 print "{0: <20s} {1: <20s} {2: >5s} {3: >20s} {4: <30s}".format('OSKEXT *', 'load_addr', 'id', 'version', 'name')
1219 format_string = "{0: <#020x} {1: <20s} {2: >5s} {3: >20s} {4: <30s}"
1220
1221 while index < kext_count:
1222 kext_dict = GetObjectAtIndexFromArray(kext_dictionary, index)
1223 kext_name = str(kext_dict.key.string)
1224 osk = Cast(kext_dict.value, 'OSKext *')
1225 if int(osk.flags.loaded) :
1226 load_addr = "{0: <#020x}".format(osk.kmod_info)
1227 id = "{0: >5d}".format(osk.loadTag)
1228 else:
1229 load_addr = "------"
1230 id = "--"
1231 version_num = unsigned(osk.version)
1232 version = GetOSKextVersion(version_num)
1233 print format_string.format(osk, load_addr, id, version, kext_name)
1234 index += 1
1235
1236 return
1237
1238@lldb_command('showkmodaddr')
1239def ShowKmodAddr(cmd_args=[]):
1240 """ Given an address, print the offset and name for the kmod containing it
1241 Syntax: (lldb) showkmodaddr <addr>
1242 """
1243 if len(cmd_args) < 1:
1244 raise ArgumentError("Insufficient arguments")
1245
1246 addr = ArgumentStringToInt(cmd_args[0])
1247 kmod_val = kern.globals.kmod
1248 for kval in IterateLinkedList(kmod_val, 'next'):
1249 if addr >= unsigned(kval.address) and addr <= (unsigned(kval.address) + unsigned(kval.size)):
1250 print GetKextSummary.header
1251 print GetKextSummary(kval) + " offset = {0: #0x}".format((addr - unsigned(kval.address)))
1252 return True
1253 return False
1254
fe8ab488 1255@lldb_command('addkext','AF:N:')
39236c6e
A
1256def AddKextSyms(cmd_args=[], cmd_options={}):
1257 """ Add kext symbols into lldb.
1258 This command finds symbols for a uuid and load the required executable
1259 Usage:
1260 addkext <uuid> : Load one kext based on uuid. eg. (lldb)addkext 4DD2344C0-4A81-3EAB-BDCF-FEAFED9EB73E
1261 addkext -F <abs/path/to/executable> <load_address> : Load kext executable at specified load address
1262 addkext -N <name> : Load one kext that matches the name provided. eg. (lldb) addkext -N corecrypto
fe8ab488 1263 addkext -N <name> -A: Load all kext that matches the name provided. eg. to load all kext with Apple in name do (lldb) addkext -N Apple -A
39236c6e
A
1264 addkext all : Will load all the kext symbols - SLOW
1265 """
1266
1267
1268 if "-F" in cmd_options:
1269 exec_path = cmd_options["-F"]
1270 exec_full_path = ResolveFSPath(exec_path)
1271 if not os.path.exists(exec_full_path):
1272 raise ArgumentError("Unable to resolve {:s}".format(exec_path))
1273
1274 if not os.path.isfile(exec_full_path):
1275 raise ArgumentError("Path is {:s} not a filepath. \nPlease check that path points to executable.\
1276\nFor ex. path/to/Symbols/IOUSBFamily.kext/Contents/PlugIns/AppleUSBHub.kext/Contents/MacOS/AppleUSBHub.\
1277\nNote: LLDB does not support adding kext based on directory paths like gdb used to.".format(exec_path))
1278 if not os.access(exec_full_path, os.X_OK):
1279 raise ArgumentError("Path is {:s} not an executable file".format(exec_path))
1280
1281 slide_value = None
1282 if cmd_args:
1283 slide_value = cmd_args[0]
1284 debuglog("loading slide value from user input %s" % cmd_args[0])
1285
1286 filespec = lldb.SBFileSpec(exec_full_path, False)
1287 print "target modules add %s" % exec_full_path
1288 print lldb_run_command("target modules add %s" % exec_full_path)
1289 loaded_module = LazyTarget.GetTarget().FindModule(filespec)
1290 if loaded_module.IsValid():
1291 uuid_str = loaded_module.GetUUIDString()
1292 debuglog("added module %s with uuid %s" % (exec_full_path, uuid_str))
1293 if slide_value is None:
1294 all_kexts_info = GetKextLoadInformation()
1295 for k in all_kexts_info:
1296 debuglog(k[0])
1297 if k[0].lower() == uuid_str.lower():
1298 slide_value = k[1]
1299 debuglog("found the slide %s for uuid %s" % (k[1], k[0]))
1300
1301 if slide_value is None:
1302 raise ArgumentError("Unable to find load address for module described at %s " % exec_full_path)
1303 load_cmd = "target modules load --file %s --slide %s" % (exec_full_path, str(slide_value))
1304 print load_cmd
1305 print lldb_run_command(load_cmd)
1306 kern.symbolicator = None
1307 return True
1308
1309 all_kexts_info = GetKextLoadInformation()
1310
1311 if "-N" in cmd_options:
1312 kext_name = cmd_options["-N"]
1313 kext_name_matches = GetLongestMatchOption(kext_name, [str(x[2]) for x in all_kexts_info], True)
fe8ab488 1314 if len(kext_name_matches) != 1 and "-A" not in cmd_options:
39236c6e
A
1315 print "Ambiguous match for name: {:s}".format(kext_name)
1316 if len(kext_name_matches) > 0:
1317 print "Options are:\n\t" + "\n\t".join(kext_name_matches)
1318 return
1319 debuglog("matched the kext to name %s and uuid %s" % (kext_name_matches[0], kext_name))
fe8ab488
A
1320 for cur_knm in kext_name_matches:
1321 for x in all_kexts_info:
1322 if cur_knm == x[2]:
1323 cur_uuid = x[0].lower()
1324 print "Fetching dSYM for {:s}".format(cur_uuid)
1325 info = dsymForUUID(cur_uuid)
1326 if info and 'DBGSymbolRichExecutable' in info:
1327 print "Adding dSYM ({0:s}) for {1:s}".format(cur_uuid, info['DBGSymbolRichExecutable'])
1328 addDSYM(cur_uuid, info)
1329 loadDSYM(cur_uuid, int(x[1],16))
1330 else:
1331 print "Failed to get symbol info for {:s}".format(cur_uuid)
1332 break
39236c6e
A
1333 kern.symbolicator = None
1334 return
1335
1336 if len(cmd_args) < 1:
1337 raise ArgumentError("No arguments specified.")
1338
1339 uuid = cmd_args[0].lower()
1340
1341 load_all_kexts = False
1342 if uuid == "all":
1343 load_all_kexts = True
1344
1345 if not load_all_kexts and len(uuid_regex.findall(uuid)) == 0:
1346 raise ArgumentError("Unknown argument {:s}".format(uuid))
1347
1348 for k_info in all_kexts_info:
1349 cur_uuid = k_info[0].lower()
1350 if load_all_kexts or (uuid == cur_uuid):
1351 print "Fetching dSYM for %s" % cur_uuid
1352 info = dsymForUUID(cur_uuid)
1353 if info and 'DBGSymbolRichExecutable' in info:
1354 print "Adding dSYM (%s) for %s" % (cur_uuid, info['DBGSymbolRichExecutable'])
1355 addDSYM(cur_uuid, info)
1356 loadDSYM(cur_uuid, int(k_info[1],16))
1357 else:
1358 print "Failed to get symbol info for %s" % cur_uuid
1359 #end of for loop
1360 kern.symbolicator = None
1361 return True
1362
1363
1364
1365lldb_alias('showkmod', 'showkmodaddr')
1366lldb_alias('showkext', 'showkmodaddr')
1367lldb_alias('showkextaddr', 'showkmodaddr')
1368
1369@lldb_type_summary(['mount *'])
fe8ab488 1370@header("{0: <20s} {1: <20s} {2: <20s} {3: <12s} {4: <12s} {5: <12s} {6: >6s} {7: <30s} {8: <35s} {9: <30s}".format('volume(mp)', 'mnt_data', 'mnt_devvp', 'flag', 'kern_flag', 'lflag', 'type', 'mnton', 'mntfrom', 'iosched supported'))
39236c6e
A
1371def GetMountSummary(mount):
1372 """ Display a summary of mount on the system
1373 """
1374 out_string = ("{mnt: <#020x} {mnt.mnt_data: <#020x} {mnt.mnt_devvp: <#020x} {mnt.mnt_flag: <#012x} " +
1375 "{mnt.mnt_kern_flag: <#012x} {mnt.mnt_lflag: <#012x} {vfs.f_fstypename: >6s} " +
fe8ab488 1376 "{vfs.f_mntonname: <30s} {vfs.f_mntfromname: <35s} {iomode: <30s}").format(mnt=mount, vfs=mount.mnt_vfsstat, iomode=('Yes' if (mount.mnt_ioflags & 0x4) else 'No'))
39236c6e
A
1377 return out_string
1378
1379@lldb_command('showallmounts')
1380def ShowAllMounts(cmd_args=None):
1381 """ Print all mount points
1382 """
1383 mntlist = kern.globals.mountlist
1384 print GetMountSummary.header
1385 for mnt in IterateTAILQ_HEAD(mntlist, 'mnt_list'):
1386 print GetMountSummary(mnt)
1387 return
1388
1389lldb_alias('ShowAllVols', 'showallmounts')
1390
1391@lldb_command('systemlog')
1392def ShowSystemLog(cmd_args=None):
1393 """ Display the kernel's printf ring buffer """
1394 msgbufp = kern.globals.msgbufp
1395 msg_size = int(msgbufp.msg_size)
1396 msg_bufx = int(msgbufp.msg_bufx)
1397 msg_bufr = int(msgbufp.msg_bufr)
1398 msg_bufc = msgbufp.msg_bufc
1399 msg_bufc_data = msg_bufc.GetSBValue().GetPointeeData(0, msg_size)
1400
1401 # the buffer is circular; start at the write pointer to end,
1402 # then from beginning to write pointer
1403 line = ''
1404 err = lldb.SBError()
1405 for i in range(msg_bufx, msg_size) + range(0, msg_bufx) :
1406 err.Clear()
1407 cbyte = msg_bufc_data.GetUnsignedInt8(err, i)
1408 if not err.Success() :
fe8ab488 1409 raise ValueError("Failed to read character at offset " + str(i) + ": " + err.GetCString())
39236c6e
A
1410 c = chr(cbyte)
1411 if c == '\0' :
1412 continue
1413 elif c == '\n' :
1414 print line
1415 line = ''
1416 else :
1417 line += c
1418
1419 if len(line) > 0 :
1420 print line
1421
1422 return
1423
1424@static_var('output','')
1425def _GetVnodePathName(vnode, vnodename):
1426 """ Internal function to get vnode path string from vnode structure.
1427 params:
1428 vnode - core.value
1429 vnodename - str
1430 returns Nothing. The output will be stored in the static variable.
1431 """
1432 if not vnode:
1433 return
1434 if int(vnode.v_flag) & 0x1 and int(hex(vnode.v_mount), 16) !=0:
1435 if int(vnode.v_mount.mnt_vnodecovered):
1436 _GetVnodePathName(vnode.v_mount.mnt_vnodecovered, str(vnode.v_mount.mnt_vnodecovered.v_name) )
1437 else:
1438 _GetVnodePathName(vnode.v_parent, str(vnode.v_parent.v_name))
1439 _GetVnodePathName.output += "/%s" % vnodename
1440
1441def GetVnodePath(vnode):
1442 """ Get string representation of the vnode
1443 params: vnodeval - value representing vnode * in the kernel
1444 return: str - of format /path/to/something
1445 """
1446 out_str = ''
1447 if vnode:
1448 if (int(vnode.v_flag) & 0x000001) and int(hex(vnode.v_mount), 16) != 0 and (int(vnode.v_mount.mnt_flag) & 0x00004000) :
1449 out_str += "/"
1450 else:
1451 _GetVnodePathName.output = ''
1452 if abs(vnode.v_name) != 0:
1453 _GetVnodePathName(vnode, str(vnode.v_name))
1454 out_str += _GetVnodePathName.output
1455 else:
1456 out_str += 'v_name = NULL'
1457 _GetVnodePathName.output = ''
1458 return out_str
1459
1460
1461@lldb_command('showvnodepath')
1462def ShowVnodePath(cmd_args=None):
1463 """ Prints the path for a vnode
1464 usage: showvnodepath <vnode>
1465 """
1466 if cmd_args != None and len(cmd_args) > 0 :
1467 vnode_val = kern.GetValueFromAddress(cmd_args[0], 'vnode *')
1468 if vnode_val:
1469 print GetVnodePath(vnode_val)
1470 return
1471
1472# Macro: showvnodedev
1473def GetVnodeDevInfo(vnode):
1474 """ Internal function to get information from the device type vnodes
1475 params: vnode - value representing struct vnode *
1476 return: str - formatted output information for block and char vnode types passed as param
1477 """
1478 vnodedev_output = ""
1479 vblk_type = GetEnumValue('vtype::VBLK')
1480 vchr_type = GetEnumValue('vtype::VCHR')
1481 if (vnode.v_type == vblk_type) or (vnode.v_type == vchr_type):
1482 devnode = Cast(vnode.v_data, 'devnode_t *')
1483 devnode_dev = devnode.dn_typeinfo.dev
1484 devnode_major = (devnode_dev >> 24) & 0xff
1485 devnode_minor = devnode_dev & 0x00ffffff
1486
1487 # boilerplate device information for a vnode
1488 vnodedev_output += "Device Info:\n\t vnode:\t\t{:#x}".format(vnode)
1489 vnodedev_output += "\n\t type:\t\t"
1490 if (vnode.v_type == vblk_type):
1491 vnodedev_output += "VBLK"
1492 if (vnode.v_type == vchr_type):
1493 vnodedev_output += "VCHR"
1494 vnodedev_output += "\n\t name:\t\t{:<s}".format(vnode.v_name)
1495 vnodedev_output += "\n\t major, minor:\t{:d},{:d}".format(devnode_major, devnode_minor)
1496 vnodedev_output += "\n\t mode\t\t0{:o}".format(unsigned(devnode.dn_mode))
1497 vnodedev_output += "\n\t owner (u,g):\t{:d} {:d}".format(devnode.dn_uid, devnode.dn_gid)
1498
1499 # decode device specific data
1500 vnodedev_output += "\nDevice Specific Information:\t"
1501 if (vnode.v_type == vblk_type):
1502 vnodedev_output += "Sorry, I do not know how to decode block devices yet!"
1503 vnodedev_output += "\nMaybe you can write me!"
1504
1505 if (vnode.v_type == vchr_type):
1506 # Device information; this is scanty
1507 # range check
1508 if (devnode_major > 42) or (devnode_major < 0):
1509 vnodedev_output += "Invalid major #\n"
1510 # static assignments in conf
1511 elif (devnode_major == 0):
1512 vnodedev_output += "Console mux device\n"
1513 elif (devnode_major == 2):
1514 vnodedev_output += "Current tty alias\n"
1515 elif (devnode_major == 3):
1516 vnodedev_output += "NULL device\n"
1517 elif (devnode_major == 4):
1518 vnodedev_output += "Old pty slave\n"
1519 elif (devnode_major == 5):
1520 vnodedev_output += "Old pty master\n"
1521 elif (devnode_major == 6):
1522 vnodedev_output += "Kernel log\n"
1523 elif (devnode_major == 12):
1524 vnodedev_output += "Memory devices\n"
1525 # Statically linked dynamic assignments
1526 elif unsigned(kern.globals.cdevsw[devnode_major].d_open) == unsigned(kern.GetLoadAddressForSymbol('ptmx_open')):
1527 vnodedev_output += "Cloning pty master not done\n"
1528 #GetVnodeDevCpty(devnode_major, devnode_minor)
1529 elif unsigned(kern.globals.cdevsw[devnode_major].d_open) == unsigned(kern.GetLoadAddressForSymbol('ptsd_open')):
1530 vnodedev_output += "Cloning pty slave not done\n"
1531 #GetVnodeDevCpty(devnode_major, devnode_minor)
1532 else:
1533 vnodedev_output += "RESERVED SLOT\n"
1534 else:
1535 vnodedev_output += "{:#x} is not a device".format(vnode)
1536 return vnodedev_output
1537
1538@lldb_command('showvnodedev')
1539def ShowVnodeDev(cmd_args=None):
1540 """ Routine to display details of all vnodes of block and character device types
1541 Usage: showvnodedev <address of vnode>
1542 """
1543 if not cmd_args:
1544 print "No arguments passed"
1545 print ShowVnodeDev.__doc__
1546 return False
1547 vnode_val = kern.GetValueFromAddress(cmd_args[0], 'vnode *')
1548 if not vnode_val:
1549 print "unknown arguments:", str(cmd_args)
1550 return False
1551 print GetVnodeDevInfo(vnode_val)
1552
1553# EndMacro: showvnodedev
1554
1555# Macro: showvnodelocks
1556def GetVnodeLock(lockf):
1557 """ Internal function to get information from the given advisory lock
1558 params: lockf - value representing v_lockf member in struct vnode *
1559 return: str - formatted output information for the advisory lock
1560 """
1561 vnode_lock_output = ''
1562 lockf_flags = lockf.lf_flags
1563 lockf_type = lockf.lf_type
1564 if lockf_flags & 0x20:
1565 vnode_lock_output += ("{: <8s}").format('flock')
1566 if lockf_flags & 0x40:
1567 vnode_lock_output += ("{: <8s}").format('posix')
1568 if lockf_flags & 0x80:
1569 vnode_lock_output += ("{: <8s}").format('prov')
1570 if lockf_flags & 0x10:
1571 vnode_lock_output += ("{: <4s}").format('W')
3e170ce0
A
1572 if lockf_flags & 0x400:
1573 vnode_lock_output += ("{: <8s}").format('ofd')
39236c6e
A
1574 else:
1575 vnode_lock_output += ("{: <4s}").format('.')
1576
1577 # POSIX file vs advisory range locks
1578 if lockf_flags & 0x40:
1579 lockf_proc = Cast(lockf.lf_id, 'proc *')
1580 vnode_lock_output += ("PID {: <18d}").format(lockf_proc.p_pid)
1581 else:
1582 vnode_lock_output += ("ID {: <#019x}").format(int(lockf.lf_id))
1583
1584 # lock type
1585 if lockf_type == 1:
1586 vnode_lock_output += ("{: <12s}").format('shared')
1587 else:
1588 if lockf_type == 3:
1589 vnode_lock_output += ("{: <12s}").format('exclusive')
1590 else:
1591 if lockf_type == 2:
1592 vnode_lock_output += ("{: <12s}").format('unlock')
1593 else:
1594 vnode_lock_output += ("{: <12s}").format('unknown')
1595
1596 # start and stop values
1597 vnode_lock_output += ("{: #018x} ..").format(lockf.lf_start)
1598 vnode_lock_output += ("{: #018x}\n").format(lockf.lf_end)
1599 return vnode_lock_output
1600
1601@header("{0: <3s} {1: <7s} {2: <3s} {3: <21s} {4: <11s} {5: ^19s} {6: ^17s}".format('*', 'type', 'W', 'held by', 'lock type', 'start', 'end'))
1602def GetVnodeLocksSummary(vnode):
1603 """ Internal function to get summary of advisory locks for the given vnode
1604 params: vnode - value representing the vnode object
1605 return: str - formatted output information for the summary of advisory locks
1606 """
1607 out_str = ''
1608 if vnode:
1609 lockf_list = vnode.v_lockf
1610 for lockf_itr in IterateLinkedList(lockf_list, 'lf_next'):
1611 out_str += ("{: <4s}").format('H')
1612 out_str += GetVnodeLock(lockf_itr)
1613 lockf_blocker = lockf_itr.lf_blkhd.tqh_first
1614 while lockf_blocker:
1615 out_str += ("{: <4s}").format('>')
1616 out_str += GetVnodeLock(lockf_blocker)
1617 lockf_blocker = lockf_blocker.lf_block.tqe_next
1618 return out_str
1619
1620@lldb_command('showvnodelocks')
1621def ShowVnodeLocks(cmd_args=None):
1622 """ Routine to display list of advisory record locks for the given vnode address
1623 Usage: showvnodelocks <address of vnode>
1624 """
1625 if not cmd_args:
1626 print "No arguments passed"
1627 print ShowVnodeLocks.__doc__
1628 return False
1629 vnode_val = kern.GetValueFromAddress(cmd_args[0], 'vnode *')
1630 if not vnode_val:
1631 print "unknown arguments:", str(cmd_args)
1632 return False
1633 print GetVnodeLocksSummary.header
1634 print GetVnodeLocksSummary(vnode_val)
1635
1636# EndMacro: showvnodelocks
1637
1638# Macro: showproclocks
1639
1640@lldb_command('showproclocks')
1641def ShowProcLocks(cmd_args=None):
1642 """ Routine to display list of advisory record locks for the given process
1643 Usage: showproclocks <address of proc>
1644 """
1645 if not cmd_args:
1646 print "No arguments passed"
1647 print ShowProcLocks.__doc__
1648 return False
1649 proc = kern.GetValueFromAddress(cmd_args[0], 'proc *')
1650 if not proc:
1651 print "unknown arguments:", str(cmd_args)
1652 return False
1653 out_str = ''
1654 proc_filedesc = proc.p_fd
1655 fd_lastfile = proc_filedesc.fd_lastfile
1656 fd_ofiles = proc_filedesc.fd_ofiles
1657 count = 0
1658 seen = 0
1659 while count <= fd_lastfile:
1660 if fd_ofiles[count]:
1661 fglob = fd_ofiles[count].f_fglob
1662 fo_type = fglob.fg_ops.fo_type
1663 if fo_type == 1:
1664 fg_data = fglob.fg_data
1665 fg_vnode = Cast(fg_data, 'vnode *')
1666 name = fg_vnode.v_name
1667 lockf_itr = fg_vnode.v_lockf
1668 if lockf_itr:
1669 if not seen:
1670 print GetVnodeLocksSummary.header
1671 seen = seen + 1
1672 out_str += ("\n( fd {:d}, name ").format(count)
1673 if not name:
1674 out_str += "(null) )\n"
1675 else:
1676 out_str += "{:s} )\n".format(name)
1677 print out_str
1678 print GetVnodeLocksSummary(fg_vnode)
1679 count = count + 1
1680 print "\n{0: d} total locks for {1: #018x}".format(seen, proc)
1681
1682# EndMacro: showproclocks
1683
1684@lldb_type_summary(['vnode_t', 'vnode *'])
fe8ab488 1685@header("{0: <20s} {1: >8s} {2: >8s} {3: <20s} {4: <6s} {5: <20s} {6: <6s} {7: <6s} {8: <35s}".format('vnode', 'usecount', 'iocount', 'v_data', 'vtype', 'parent', 'mapped', 'cs_version', 'name'))
39236c6e
A
1686def GetVnodeSummary(vnode):
1687 """ Get a summary of important information out of vnode
1688 """
1689 out_str = ''
fe8ab488 1690 format_string = "{0: <#020x} {1: >8d} {2: >8d} {3: <#020x} {4: <6s} {5: <#020x} {6: <6s} {7: <6s} {8: <35s}"
39236c6e
A
1691 usecount = int(vnode.v_usecount)
1692 iocount = int(vnode.v_iocount)
1693 v_data_ptr = int(hex(vnode.v_data), 16)
1694 vtype = int(vnode.v_type)
1695 vtype_str = "%d" % vtype
1696 vnode_types = ['VNON', 'VREG', 'VDIR', 'VBLK', 'VCHR', 'VLNK', 'VSOCK', 'VFIFO', 'VBAD', 'VSTR', 'VCPLX'] # see vnode.h for enum type definition
1697 if vtype >= 0 and vtype < len(vnode_types):
1698 vtype_str = vnode_types[vtype]
1699 parent_ptr = int(hex(vnode.v_parent), 16)
1700 name_ptr = int(hex(vnode.v_name), 16)
1701 name =""
1702 if name_ptr != 0:
1703 name = str(vnode.v_name)
1704 elif int(vnode.v_tag) == 16 :
1705 cnode = Cast(vnode.v_data, 'cnode *')
1706 name = "hfs: %s" % str( Cast(cnode.c_desc.cd_nameptr, 'char *'))
1707 mapped = '-'
fe8ab488 1708 csblob_version = '-'
39236c6e 1709 if (vtype == 1) and (vnode.v_un.vu_ubcinfo != 0):
fe8ab488 1710 csblob_version = '{: <6d}'.format(vnode.v_un.vu_ubcinfo.cs_add_gen)
39236c6e
A
1711 # Check to see if vnode is mapped/unmapped
1712 if (vnode.v_un.vu_ubcinfo.ui_flags & 0x8) != 0:
1713 mapped = '1'
1714 else:
1715 mapped = '0'
fe8ab488 1716 out_str += format_string.format(vnode, usecount, iocount, v_data_ptr, vtype_str, parent_ptr, mapped, csblob_version, name)
39236c6e
A
1717 return out_str
1718
1719@lldb_command('showallvnodes')
1720def ShowAllVnodes(cmd_args=None):
1721 """ Display info about all vnodes
1722 """
1723 mntlist = kern.globals.mountlist
1724 print GetVnodeSummary.header
1725 for mntval in IterateTAILQ_HEAD(mntlist, 'mnt_list'):
1726 for vnodeval in IterateTAILQ_HEAD(mntval.mnt_vnodelist, 'v_mntvnodes'):
1727 print GetVnodeSummary(vnodeval)
1728 return
1729
1730@lldb_command('showvnode')
1731def ShowVnode(cmd_args=None):
1732 """ Display info about one vnode
1733 usage: showvnode <vnode>
1734 """
1735 if cmd_args == None or len(cmd_args) < 1:
1736 print "Please provide valid vnode argument. Type help showvnode for help."
1737 return
1738 vnodeval = kern.GetValueFromAddress(cmd_args[0],'vnode *')
1739 print GetVnodeSummary.header
1740 print GetVnodeSummary(vnodeval)
1741
1742@lldb_command('showvolvnodes')
1743def ShowVolVnodes(cmd_args=None):
1744 """ Display info about all vnodes of a given mount_t
1745 """
1746 if cmd_args == None or len(cmd_args) < 1:
1747 print "Please provide a valide mount_t argument. Try 'help showvolvnodes' for help"
1748 return
1749 mntval = kern.GetValueFromAddress(cmd_args[0], 'mount_t')
1750 print GetVnodeSummary.header
1751 for vnodeval in IterateTAILQ_HEAD(mntval.mnt_vnodelist, 'v_mntvnodes'):
1752 print GetVnodeSummary(vnodeval)
1753 return
1754
1755@lldb_command('showvolbusyvnodes')
1756def ShowVolBusyVnodes(cmd_args=None):
1757 """ Display info about busy (iocount!=0) vnodes of a given mount_t
1758 """
1759 if cmd_args == None or len(cmd_args) < 1:
1760 print "Please provide a valide mount_t argument. Try 'help showvolbusyvnodes' for help"
1761 return
1762 mntval = kern.GetValueFromAddress(cmd_args[0], 'mount_t')
1763 print GetVnodeSummary.header
1764 for vnodeval in IterateTAILQ_HEAD(mntval.mnt_vnodelist, 'v_mntvnodes'):
1765 if int(vnodeval.v_iocount) != 0:
1766 print GetVnodeSummary(vnodeval)
1767
1768@lldb_command('showallbusyvnodes')
1769def ShowAllBusyVnodes(cmd_args=None):
1770 """ Display info about all busy (iocount!=0) vnodes
1771 """
1772 mntlistval = kern.globals.mountlist
1773 for mntval in IterateTAILQ_HEAD(mntlistval, 'mnt_list'):
1774 ShowVolBusyVnodes([hex(mntval)])
1775
1776@lldb_command('print_vnode')
1777def PrintVnode(cmd_args=None):
1778 """ Prints out the fields of a vnode struct
1779 Usage: print_vnode <vnode>
1780 """
1781 if not cmd_args:
1782 print "Please provide valid vnode argument. Type help print_vnode for help."
1783 return
1784 ShowVnode(cmd_args)
1785
1786@lldb_command('showworkqvnodes')
1787def ShowWorkqVnodes(cmd_args=None):
1788 """ Print the vnode worker list
1789 Usage: showworkqvnodes <struct mount *>
1790 """
1791 if not cmd_args:
1792 print "Please provide valid mount argument. Type help showworkqvnodes for help."
1793 return
1794
1795 mp = kern.GetValueFromAddress(cmd_args[0], 'mount *')
1796 vp = Cast(mp.mnt_workerqueue.tqh_first, 'vnode *')
1797 print GetVnodeSummary.header
1798 while int(vp) != 0:
1799 print GetVnodeSummary(vp)
1800 vp = vp.v_mntvnodes.tqe_next
1801
1802@lldb_command('shownewvnodes')
1803def ShowNewVnodes(cmd_args=None):
1804 """ Print the new vnode list
1805 Usage: shownewvnodes <struct mount *>
1806 """
1807 if not cmd_args:
1808 print "Please provide valid mount argument. Type help shownewvnodes for help."
1809 return
1810 mp = kern.GetValueFromAddress(cmd_args[0], 'mount *')
1811 vp = Cast(mp.mnt_newvnodes.tqh_first, 'vnode *')
1812 print GetVnodeSummary.header
1813 while int(vp) != 0:
1814 print GetVnodeSummary(vp)
1815 vp = vp.v_mntvnodes.tqe_next
1816
1817
1818@lldb_command('showprocvnodes')
1819def ShowProcVnodes(cmd_args=None):
1820 """ Routine to print out all the open fds which are vnodes in a process
1821 Usage: showprocvnodes <proc *>
1822 """
1823 if not cmd_args:
1824 print "Please provide valid proc argument. Type help showprocvnodes for help."
1825 return
1826 procptr = kern.GetValueFromAddress(cmd_args[0], 'proc *')
1827 fdptr = Cast(procptr.p_fd, 'filedesc *')
1828 if int(fdptr.fd_cdir) != 0:
1829 print '{0: <25s}\n{1: <s}\n{2: <s}'.format('Current Working Directory:', GetVnodeSummary.header, GetVnodeSummary(fdptr.fd_cdir))
1830 if int(fdptr.fd_rdir) != 0:
1831 print '{0: <25s}\n{1: <s}\n{2: <s}'.format('Current Root Directory:', GetVnodeSummary.header, GetVnodeSummary(fdptr.fd_rdir))
1832 count = 0
1833 print '\n' + '{0: <5s} {1: <7s}'.format('fd', 'flags') + GetVnodeSummary.header
1834 # Hack to get around <rdar://problem/12879494> llb fails to cast addresses to double pointers
1835 fpptr = Cast(fdptr.fd_ofiles, 'fileproc *')
1836 while count < fdptr.fd_nfiles:
1837 fpp = dereference(fpptr)
1838 fproc = Cast(fpp, 'fileproc *')
1839 if int(fproc) != 0:
1840 fglob = dereference(fproc).f_fglob
1841 flags = ""
1842 if (int(fglob) != 0) and (int(fglob.fg_ops.fo_type) == 1):
1843 if (fdptr.fd_ofileflags[count] & 1): flags += 'E'
1844 if (fdptr.fd_ofileflags[count] & 2): flags += 'F'
1845 if (fdptr.fd_ofileflags[count] & 4): flags += 'R'
1846 if (fdptr.fd_ofileflags[count] & 8): flags += 'C'
1847 print '{0: <5d} {1: <7s}'.format(count, flags) + GetVnodeSummary(Cast(fglob.fg_data, 'vnode *'))
1848 count += 1
1849 fpptr = kern.GetValueFromAddress(int(fpptr) + kern.ptrsize,'fileproc *')
1850
1851@lldb_command('showallprocvnodes')
1852def ShowAllProcVnodes(cmd_args=None):
1853 """ Routine to print out all the open fds which are vnodes
1854 """
1855
1856 procptr = Cast(kern.globals.allproc.lh_first, 'proc *')
1857 while procptr and int(procptr) != 0:
1858 print '{:<s}'.format("=" * 106)
1859 print GetProcInfo(procptr)
1860 ShowProcVnodes([int(procptr)])
1861 procptr = procptr.p_list.le_next
1862
1863@xnudebug_test('test_vnode')
1864def TestShowAllVnodes(kernel_target, config, lldb_obj, isConnected ):
1865 """ Test the functionality of vnode related commands
1866 returns
1867 - False on failure
1868 - True on success
1869 """
1870 if not isConnected:
1871 print "Target is not connected. Cannot test memstats"
1872 return False
1873 res = lldb.SBCommandReturnObject()
1874 lldb_obj.debugger.GetCommandInterpreter().HandleCommand("showallvnodes", res)
1875 result = res.GetOutput()
1876 if len(result.split("\n")) > 2 and result.find('VREG') != -1 and len(result.splitlines()[2].split()) > 5:
1877 return True
1878 else:
1879 return False
1880
1881# Macro: showallmtx
1882@lldb_type_summary(['_lck_grp_ *'])
1883def GetMutexEntry(mtxg):
1884 """ Summarize a mutex group entry with important information.
1885 params:
1886 mtxg: value - obj representing a mutex group in kernel
1887 returns:
1888 out_string - summary of the mutex group
1889 """
1890 out_string = ""
1891
1892 if kern.ptrsize == 8:
1893 format_string = '{0:#018x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1894 else:
1895 format_string = '{0:#010x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1896
1897 if mtxg.lck_grp_mtxcnt:
1898 out_string += format_string.format(mtxg, mtxg.lck_grp_mtxcnt,mtxg.lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_util_cnt,
1899 mtxg.lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_miss_cnt,
1900 mtxg.lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_wait_cnt, mtxg.lck_grp_name)
1901 return out_string
1902
1903@lldb_command('showallmtx')
1904def ShowAllMtx(cmd_args=None):
1905 """ Routine to print a summary listing of all mutexes
1906 """
1907
1908 if kern.ptrsize == 8:
1909 hdr_format = '{:<18s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
1910 else:
1911 hdr_format = '{:<10s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
1912
1913 print hdr_format.format('LCK GROUP', 'CNT', 'UTIL', 'MISS', 'WAIT', 'NAME')
1914
1915 mtxgrp_queue_head = kern.globals.lck_grp_queue
1916 mtxgrp_ptr_type = GetType('_lck_grp_ *')
1917
1918 for mtxgrp_ptr in IterateQueue(mtxgrp_queue_head, mtxgrp_ptr_type, "lck_grp_link"):
1919 print GetMutexEntry(mtxgrp_ptr)
1920 return
1921# EndMacro: showallmtx
1922
1923# Macro: showallrwlck
1924@lldb_type_summary(['_lck_grp_ *'])
1925def GetRWLEntry(rwlg):
1926 """ Summarize a reader writer lock group with important information.
1927 params:
1928 rwlg: value - obj representing a reader writer lock group in kernel
1929 returns:
1930 out_string - summary of the reader writer lock group
1931 """
1932 out_string = ""
1933
1934 if kern.ptrsize == 8:
1935 format_string = '{0:#018x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1936 else:
1937 format_string = '{0:#010x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1938
1939 if rwlg.lck_grp_rwcnt:
1940 out_string += format_string.format(rwlg, rwlg.lck_grp_rwcnt,rwlg.lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_util_cnt,
1941 rwlg.lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_miss_cnt,
1942 rwlg.lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_wait_cnt, rwlg.lck_grp_name)
1943 return out_string
1944
15129b1c
A
1945#Macro: showlock
1946@lldb_type_summary(['lck_mtx_t *'])
1947@header("===== Mutex Lock Summary =====")
1948def GetMutexLockSummary(mtx):
1949 """ Summarize mutex lock with important information.
1950 params:
1951 mtx: value - obj representing a mutex lock in kernel
1952 returns:
1953 out_str - summary of the mutex lock
1954 """
1955 if not mtx:
1956 return "Invalid lock value: 0x0"
1957
1958 if kern.arch == "x86_64":
1959 out_str = "Lock Type\t\t: MUTEX\n"
1960 mtxd = mtx.lck_mtx_sw.lck_mtxd
1961 out_str += "Owner Thread\t\t: {:#x}\n".format(mtxd.lck_mtxd_owner)
1962 cmd_str = "p/d ((lck_mtx_t*){:#x})->lck_mtx_sw.lck_mtxd.".format(mtx)
1963 cmd_out = lldb_run_command(cmd_str + "lck_mtxd_waiters")
1964 out_str += "Number of Waiters\t: {:s}\n".format(cmd_out.split()[-1])
1965 cmd_out = lldb_run_command(cmd_str + "lck_mtxd_ilocked")
1966 out_str += "ILocked\t\t\t: {:s}\n".format(cmd_out.split()[-1])
1967 cmd_out = lldb_run_command(cmd_str + "lck_mtxd_mlocked")
1968 out_str += "MLocked\t\t\t: {:s}\n".format(cmd_out.split()[-1])
1969 cmd_out = lldb_run_command(cmd_str + "lck_mtxd_promoted")
1970 out_str += "Promoted\t\t: {:s}\n".format(cmd_out.split()[-1])
1971 cmd_out = lldb_run_command(cmd_str + "lck_mtxd_spin")
1972 out_str += "Spin\t\t\t: {:s}\n".format(cmd_out.split()[-1])
1973 return out_str
1974
1975 out_str = "Lock Type\t\t: MUTEX\n"
1976 out_str += "Owner Thread\t\t: {:#x}\n".format(mtx.lck_mtx_hdr.lck_mtxd_data & ~0x3)
1977 out_str += "Number of Waiters\t: {:d}\n".format(mtx.lck_mtx_sw.lck_mtxd.lck_mtxd_waiters)
1978 out_str += "Flags\t\t\t: "
1979 if mtx.lck_mtx_hdr.lck_mtxd_data & 0x1:
1980 out_str += "[Interlock Locked] "
1981 if mtx.lck_mtx_hdr.lck_mtxd_data & 0x2:
1982 out_str += "[Wait Flag]"
1983 if (mtx.lck_mtx_hdr.lck_mtxd_data & 0x3) == 0:
1984 out_str += "None"
1985 return out_str
1986
1987@lldb_type_summary(['lck_spin_t *'])
1988@header("===== SpinLock Summary =====")
1989def GetSpinLockSummary(spinlock):
1990 """ Summarize spinlock with important information.
1991 params:
1992 spinlock: value - obj representing a spinlock in kernel
1993 returns:
1994 out_str - summary of the spinlock
1995 """
1996 if not spinlock:
1997 return "Invalid lock value: 0x0"
1998
1999 out_str = "Lock Type\t\t: SPINLOCK\n"
2000 if kern.arch == "x86_64":
2001 out_str += "Interlock\t\t: {:#x}\n".format(spinlock.interlock)
2002 return out_str
2003
2004 out_str += "Owner Thread\t\t: {:#x}\n".format(spinlock.lck_spin_data & ~0x3)
2005 out_str += "Flags\t\t\t: "
2006 if spinlock.lck_spin_data & 0x1:
2007 out_str += "[Interlock Locked] "
2008 if spinlock.lck_spin_data & 0x2:
2009 out_str += "[Wait Flag]"
2010 if (spinlock.lck_spin_data & 0x3) == 0:
2011 out_str += "None"
2012 return out_str
2013
2014@lldb_command('showlock', 'MS')
2015def ShowLock(cmd_args=None, cmd_options={}):
2016 """ Show info about a lock - its state and owner thread details
2017 Usage: showlock <address of a lock>
2018 -M : to consider <addr> as lck_mtx_t
2019 -S : to consider <addr> as lck_spin_t
2020 """
2021 if not cmd_args:
2022 raise ArgumentError("Please specify the address of the lock whose info you want to view.")
2023 return
2024
2025 summary_str = ""
2026 lock = kern.GetValueFromAddress(cmd_args[0], 'uintptr_t*')
2027
2028 if kern.arch == "x86_64" and lock:
2029 if "-M" in cmd_options:
2030 lock_mtx = Cast(lock, 'lck_mtx_t *')
2031 summary_str = GetMutexLockSummary(lock_mtx)
2032 elif "-S" in cmd_options:
2033 lock_spin = Cast(lock, 'lck_spin_t *')
2034 summary_str = GetSpinLockSummary(lock_spin)
2035 else:
2036 summary_str = "Please specify supported lock option(-M/-S)"
2037
2038 print summary_str
2039 return
2040
2041 if lock:
2042 lock_mtx = Cast(lock, 'lck_mtx_t*')
2043 if lock_mtx.lck_mtx_type == 0x22:
2044 summary_str = GetMutexLockSummary(lock_mtx)
2045
2046 lock_spin = Cast(lock, 'lck_spin_t*')
2047 if lock_spin.lck_spin_type == 0x11:
2048 summary_str = GetSpinLockSummary(lock_spin)
2049
2050 if summary_str == "":
2051 summary_str = "Lock Type\t\t: INVALID LOCK"
2052 print summary_str
2053
2054#EndMacro: showlock
2055
39236c6e
A
2056@lldb_command('showallrwlck')
2057def ShowAllRWLck(cmd_args=None):
2058 """ Routine to print a summary listing of all read/writer locks
2059 """
2060 if kern.ptrsize == 8:
2061 hdr_format = '{:<18s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
2062 else:
2063 hdr_format = '{:<10s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
2064
2065 print hdr_format.format('LCK GROUP', 'CNT', 'UTIL', 'MISS', 'WAIT', 'NAME')
2066
2067 rwlgrp_queue_head = kern.globals.lck_grp_queue
2068 rwlgrp_ptr_type = GetType('_lck_grp_ *')
2069 for rwlgrp_ptr in IterateQueue(rwlgrp_queue_head, rwlgrp_ptr_type, "lck_grp_link"):
2070 print GetRWLEntry(rwlgrp_ptr)
2071 return
2072# EndMacro: showallrwlck
2073
2074#Macro: showbootermemorymap
2075@lldb_command('showbootermemorymap')
2076def ShowBooterMemoryMap(cmd_args=None):
2077 """ Prints out the phys memory map from kernelBootArgs
2078 Supported only on x86_64
2079 """
2080 if kern.arch == 'x86_64':
2081 voffset = unsigned(0xFFFFFF8000000000)
2082 else:
2083 print "showbootermemorymap not supported on this architecture"
2084 return
2085
2086 out_string = ""
2087
2088 # Memory type map
2089 memtype_dict = {
2090 0: 'Reserved',
2091 1: 'LoaderCode',
2092 2: 'LoaderData',
2093 3: 'BS_code',
2094 4: 'BS_data',
2095 5: 'RT_code',
2096 6: 'RT_data',
2097 7: 'Convention',
2098 8: 'Unusable',
2099 9: 'ACPI_recl',
2100 10: 'ACPI_NVS',
2101 11: 'MemMapIO',
2102 12: 'MemPortIO',
2103 13: 'PAL_code'
2104 }
2105
2106 boot_args = kern.globals.kernelBootArgs
2107 msize = boot_args.MemoryMapDescriptorSize
2108 mcount = (boot_args.MemoryMapSize) / unsigned(msize)
2109
2110 out_string += "{0: <12s} {1: <19s} {2: <19s} {3: <19s} {4: <10s}\n".format("Type", "Physical Start", "Number of Pages", "Virtual Start", "Attributes")
2111
2112 i = 0
2113 while i < mcount:
2114 mptr = kern.GetValueFromAddress(unsigned(boot_args.MemoryMap) + voffset + unsigned(i*msize), 'EfiMemoryRange *')
2115 mtype = unsigned(mptr.Type)
2116 if mtype in memtype_dict:
2117 out_string += "{0: <12s}".format(memtype_dict[mtype])
2118 else:
2119 out_string += "{0: <12s}".format("UNKNOWN")
2120
2121 if mptr.VirtualStart == 0:
2122 out_string += "{0: #019x} {1: #019x} {2: <19s} {3: #019x}\n".format(mptr.PhysicalStart, mptr.NumberOfPages, ' '*19, mptr.Attribute)
2123 else:
2124 out_string += "{0: #019x} {1: #019x} {2: #019x} {3: #019x}\n".format(mptr.PhysicalStart, mptr.NumberOfPages, mptr.VirtualStart, mptr.Attribute)
2125 i = i + 1
2126
2127 print out_string
2128#EndMacro: showbootermemorymap
2129
fe8ab488
A
2130@lldb_command('show_all_purgeable_objects')
2131def ShowAllPurgeableVmObjects(cmd_args=None):
2132 """ Routine to print a summary listing of all the purgeable vm objects
2133 """
2134 print "\n-------------------- VOLATILE OBJECTS --------------------\n"
2135 ShowAllPurgeableVolatileVmObjects()
2136 print "\n-------------------- NON-VOLATILE OBJECTS --------------------\n"
2137 ShowAllPurgeableNonVolatileVmObjects()
2138
2139@lldb_command('show_all_purgeable_nonvolatile_objects')
2140def ShowAllPurgeableNonVolatileVmObjects(cmd_args=None):
2141 """ Routine to print a summary listing of all the vm objects in
2142 the purgeable_nonvolatile_queue
2143 """
2144
2145 nonvolatile_total = lambda:None
2146 nonvolatile_total.objects = 0
2147 nonvolatile_total.vsize = 0
2148 nonvolatile_total.rsize = 0
2149 nonvolatile_total.wsize = 0
2150 nonvolatile_total.csize = 0
2151 nonvolatile_total.disowned_objects = 0
2152 nonvolatile_total.disowned_vsize = 0
2153 nonvolatile_total.disowned_rsize = 0
2154 nonvolatile_total.disowned_wsize = 0
2155 nonvolatile_total.disowned_csize = 0
2156
2157 queue_len = kern.globals.purgeable_nonvolatile_count
2158 queue_head = kern.globals.purgeable_nonvolatile_queue
2159
2160 print 'purgeable_nonvolatile_queue:{:#018x} purgeable_volatile_count:{:d}\n'.format(kern.GetLoadAddressForSymbol('purgeable_nonvolatile_queue'),queue_len)
2161 print 'N:non-volatile V:volatile E:empty D:deny\n'
2162
2163 print '{:>6s} {:<6s} {:18s} {:1s} {:>6s} {:>16s} {:>10s} {:>10s} {:>10s} {:18s} {:>6s} {:<20s}\n'.format("#","#","object","P","refcnt","size (pages)","resid","wired","compressed","owner","pid","process")
2164 idx = 0
2165 for object in IterateQueue(queue_head, 'struct vm_object *', 'objq'):
2166 idx += 1
2167 ShowPurgeableNonVolatileVmObject(object, idx, queue_len, nonvolatile_total)
2168 print "disowned objects:{:<10d} [ virtual:{:<10d} resident:{:<10d} wired:{:<10d} compressed:{:<10d} ]\n".format(nonvolatile_total.disowned_objects, nonvolatile_total.disowned_vsize, nonvolatile_total.disowned_rsize, nonvolatile_total.disowned_wsize, nonvolatile_total.disowned_csize)
2169 print " all objects:{:<10d} [ virtual:{:<10d} resident:{:<10d} wired:{:<10d} compressed:{:<10d} ]\n".format(nonvolatile_total.objects, nonvolatile_total.vsize, nonvolatile_total.rsize, nonvolatile_total.wsize, nonvolatile_total.csize)
2170
2171
2172def ShowPurgeableNonVolatileVmObject(object, idx, queue_len, nonvolatile_total):
2173 """ Routine to print out a summary a VM object in purgeable_nonvolatile_queue
2174 params:
2175 object - core.value : a object of type 'struct vm_object *'
2176 returns:
2177 None
2178 """
3e170ce0 2179 page_size = kern.globals.page_size
fe8ab488
A
2180 if object.purgable == 0:
2181 purgable = "N"
2182 elif object.purgable == 1:
2183 purgable = "V"
2184 elif object.purgable == 2:
2185 purgable = "E"
2186 elif object.purgable == 3:
2187 purgable = "D"
2188 else:
2189 purgable = "?"
2190 if object.pager == 0:
2191 compressed_count = 0
2192 else:
2193 compressor_pager = Cast(object.pager, 'compressor_pager *')
2194 compressed_count = compressor_pager.cpgr_num_slots_occupied
2195
3e170ce0 2196 print "{:>6d}/{:<6d} {:#018x} {:1s} {:>6d} {:>16d} {:>10d} {:>10d} {:>10d} {:#018x} {:>6d} {:<20s}\n".format(idx,queue_len,object,purgable,object.ref_count,object.vo_un1.vou_size/page_size,object.resident_page_count,object.wired_page_count,compressed_count, object.vo_un2.vou_purgeable_owner,GetProcPIDForTask(object.vo_un2.vou_purgeable_owner),GetProcNameForTask(object.vo_un2.vou_purgeable_owner))
fe8ab488
A
2197
2198 nonvolatile_total.objects += 1
3e170ce0 2199 nonvolatile_total.vsize += object.vo_un1.vou_size/page_size
fe8ab488
A
2200 nonvolatile_total.rsize += object.resident_page_count
2201 nonvolatile_total.wsize += object.wired_page_count
2202 nonvolatile_total.csize += compressed_count
2203 if object.vo_un2.vou_purgeable_owner == 0:
2204 nonvolatile_total.disowned_objects += 1
3e170ce0 2205 nonvolatile_total.disowned_vsize += object.vo_un1.vou_size/page_size
fe8ab488
A
2206 nonvolatile_total.disowned_rsize += object.resident_page_count
2207 nonvolatile_total.disowned_wsize += object.wired_page_count
2208 nonvolatile_total.disowned_csize += compressed_count
2209
2210
2211@lldb_command('show_all_purgeable_volatile_objects')
2212def ShowAllPurgeableVolatileVmObjects(cmd_args=None):
2213 """ Routine to print a summary listing of all the vm objects in
2214 the purgeable queues
2215 """
2216 volatile_total = lambda:None
2217 volatile_total.objects = 0
2218 volatile_total.vsize = 0
2219 volatile_total.rsize = 0
2220 volatile_total.wsize = 0
2221 volatile_total.csize = 0
2222 volatile_total.disowned_objects = 0
2223 volatile_total.disowned_vsize = 0
2224 volatile_total.disowned_rsize = 0
2225 volatile_total.disowned_wsize = 0
2226 volatile_total.disowned_csize = 0
2227
2228 purgeable_queues = kern.globals.purgeable_queues
2229 print "---------- OBSOLETE\n"
2230 ShowPurgeableQueue(purgeable_queues[0], volatile_total)
2231 print "\n\n---------- FIFO\n"
2232 ShowPurgeableQueue(purgeable_queues[1], volatile_total)
2233 print "\n\n---------- LIFO\n"
2234 ShowPurgeableQueue(purgeable_queues[2], volatile_total)
2235
2236 print "disowned objects:{:<10d} [ virtual:{:<10d} resident:{:<10d} wired:{:<10d} compressed:{:<10d} ]\n".format(volatile_total.disowned_objects, volatile_total.disowned_vsize, volatile_total.disowned_rsize, volatile_total.disowned_wsize, volatile_total.disowned_csize)
2237 print " all objects:{:<10d} [ virtual:{:<10d} resident:{:<10d} wired:{:<10d} compressed:{:<10d} ]\n".format(volatile_total.objects, volatile_total.vsize, volatile_total.rsize, volatile_total.wsize, volatile_total.csize)
2238 purgeable_count = kern.globals.vm_page_purgeable_count
2239 purgeable_wired_count = kern.globals.vm_page_purgeable_wired_count
2240 if purgeable_count != volatile_total.rsize or purgeable_wired_count != volatile_total.wsize:
2241 mismatch = "<--------- MISMATCH\n"
2242 else:
2243 mismatch = ""
2244 print "vm_page_purgeable_count: resident:{:<10d} wired:{:<10d} {:s}\n".format(purgeable_count, purgeable_wired_count, mismatch)
2245
2246
2247def ShowPurgeableQueue(qhead, volatile_total):
2248 print "----- GROUP 0\n"
2249 ShowPurgeableGroup(qhead.objq[0], volatile_total)
2250 print "----- GROUP 1\n"
2251 ShowPurgeableGroup(qhead.objq[1], volatile_total)
2252 print "----- GROUP 2\n"
2253 ShowPurgeableGroup(qhead.objq[2], volatile_total)
2254 print "----- GROUP 3\n"
2255 ShowPurgeableGroup(qhead.objq[3], volatile_total)
2256 print "----- GROUP 4\n"
2257 ShowPurgeableGroup(qhead.objq[4], volatile_total)
2258 print "----- GROUP 5\n"
2259 ShowPurgeableGroup(qhead.objq[5], volatile_total)
2260 print "----- GROUP 6\n"
2261 ShowPurgeableGroup(qhead.objq[6], volatile_total)
2262 print "----- GROUP 7\n"
2263 ShowPurgeableGroup(qhead.objq[7], volatile_total)
2264
2265def ShowPurgeableGroup(qhead, volatile_total):
2266 idx = 0
2267 for object in IterateQueue(qhead, 'struct vm_object *', 'objq'):
2268 if idx == 0:
2269# print "{:>6s} {:18s} {:1s} {:>6s} {:>16s} {:>10s} {:>10s} {:>10s} {:18s} {:>6s} {:<20s} {:18s} {:>6s} {:<20s} {:s}\n".format("#","object","P","refcnt","size (pages)","resid","wired","compressed","owner","pid","process","volatilizer","pid","process","")
2270 print "{:>6s} {:18s} {:1s} {:>6s} {:>16s} {:>10s} {:>10s} {:>10s} {:18s} {:>6s} {:<20s}\n".format("#","object","P","refcnt","size (pages)","resid","wired","compressed","owner","pid","process")
2271 idx += 1
2272 ShowPurgeableVolatileVmObject(object, idx, volatile_total)
2273
2274def ShowPurgeableVolatileVmObject(object, idx, volatile_total):
2275 """ Routine to print out a summary a VM object in a purgeable queue
2276 params:
2277 object - core.value : a object of type 'struct vm_object *'
2278 returns:
2279 None
2280 """
2281# if int(object.vo_un2.vou_purgeable_owner) != int(object.vo_purgeable_volatilizer):
2282# diff=" !="
2283# else:
2284# diff=" "
3e170ce0 2285 page_size = kern.globals.page_size
fe8ab488
A
2286 if object.purgable == 0:
2287 purgable = "N"
2288 elif object.purgable == 1:
2289 purgable = "V"
2290 elif object.purgable == 2:
2291 purgable = "E"
2292 elif object.purgable == 3:
2293 purgable = "D"
2294 else:
2295 purgable = "?"
2296 if object.pager == 0:
2297 compressed_count = 0
2298 else:
2299 compressor_pager = Cast(object.pager, 'compressor_pager *')
2300 compressed_count = compressor_pager.cpgr_num_slots_occupied
3e170ce0
A
2301# print "{:>6d} {:#018x} {:1s} {:>6d} {:>16d} {:>10d} {:>10d} {:>10d} {:#018x} {:>6d} {:<20s} {:#018x} {:>6d} {:<20s} {:s}\n".format(idx,object,purgable,object.ref_count,object.vo_un1.vou_size/page_size,object.resident_page_count,object.wired_page_count,compressed_count,object.vo_un2.vou_purgeable_owner,GetProcPIDForTask(object.vo_un2.vou_purgeable_owner),GetProcNameForTask(object.vo_un2.vou_purgeable_owner),object.vo_purgeable_volatilizer,GetProcPIDForTask(object.vo_purgeable_volatilizer),GetProcNameForTask(object.vo_purgeable_volatilizer),diff)
2302 print "{:>6d} {:#018x} {:1s} {:>6d} {:>16d} {:>10d} {:>10d} {:>10d} {:#018x} {:>6d} {:<20s}\n".format(idx,object,purgable,object.ref_count,object.vo_un1.vou_size/page_size,object.resident_page_count,object.wired_page_count,compressed_count, object.vo_un2.vou_purgeable_owner,GetProcPIDForTask(object.vo_un2.vou_purgeable_owner),GetProcNameForTask(object.vo_un2.vou_purgeable_owner))
fe8ab488 2303 volatile_total.objects += 1
3e170ce0 2304 volatile_total.vsize += object.vo_un1.vou_size/page_size
fe8ab488
A
2305 volatile_total.rsize += object.resident_page_count
2306 volatile_total.wsize += object.wired_page_count
2307 volatile_total.csize += compressed_count
2308 if object.vo_un2.vou_purgeable_owner == 0:
2309 volatile_total.disowned_objects += 1
3e170ce0 2310 volatile_total.disowned_vsize += object.vo_un1.vou_size/page_size
fe8ab488
A
2311 volatile_total.disowned_rsize += object.resident_page_count
2312 volatile_total.disowned_wsize += object.wired_page_count
2313 volatile_total.disowned_csize += compressed_count
2314
2315
2316def GetCompressedPagesForObject(obj):
2317 """Stuff
2318 """
2319 pager = Cast(obj.pager, 'compressor_pager_t')
2320 return pager.cpgr_num_slots_occupied
2321# if pager.cpgr_num_slots > 128:
2322# slots_arr = pager.cpgr_slots.cpgr_islots
2323# num_indirect_slot_ptr = (pager.cpgr_num_slots + 127) / 128
2324# index = 0
2325# compressor_slot = 0
2326# compressed_pages = 0
2327# while index < num_indirect_slot_ptr:
2328# compressor_slot = 0
2329# if slots_arr[index]:
2330# while compressor_slot < 128:
2331# if slots_arr[index][compressor_slot]:
2332# compressed_pages += 1
2333# compressor_slot += 1
2334# index += 1
2335# else:
2336# slots_arr = pager.cpgr_slots.cpgr_dslots
2337# compressor_slot = 0
2338# compressed_pages = 0
2339# while compressor_slot < pager.cpgr_num_slots:
2340# if slots_arr[compressor_slot]:
2341# compressed_pages += 1
2342# compressor_slot += 1
2343# return compressed_pages
2344
fe8ab488
A
2345def ShowTaskVMEntries(task, show_pager_info, show_all_shadows):
2346 """ Routine to print out a summary listing of all the entries in a vm_map
2347 params:
2348 task - core.value : a object of type 'task *'
2349 returns:
2350 None
2351 """
2352 print "vm_map entries for task " + hex(task)
2353 print GetTaskSummary.header
2354 print GetTaskSummary(task)
2355 if not task.map:
2356 print "Task {0: <#020x} has map = 0x0"
2357 return None
2358 showmapvme(task.map, show_pager_info, show_all_shadows)
2359
2360@lldb_command("showmapvme", "PS")
2361def ShowMapVME(cmd_args=None, cmd_options={}):
2362 """Routine to print out info about the specified vm_map and its vm entries
2363 usage: showmapvme <vm_map>
3e170ce0
A
2364 Use -S flag to show VM object shadow chains
2365 Use -P flag to show pager info (mapped file, compressed pages, ...)
fe8ab488
A
2366 """
2367 if cmd_args == None or len(cmd_args) < 1:
2368 print "Invalid argument.", ShowMap.__doc__
2369 return
2370 show_pager_info = False
2371 show_all_shadows = False
2372 if "-P" in cmd_options:
2373 show_pager_info = True
2374 if "-S" in cmd_options:
2375 show_all_shadows = True
2376 map = kern.GetValueFromAddress(cmd_args[0], 'vm_map_t')
2377 showmapvme(map, show_pager_info, show_all_shadows)
2378
2379def showmapvme(map, show_pager_info, show_all_shadows):
3e170ce0 2380 page_size = kern.globals.page_size
fe8ab488
A
2381 vnode_pager_ops = kern.globals.vnode_pager_ops
2382 vnode_pager_ops_addr = unsigned(addressof(vnode_pager_ops))
2383 rsize = 0
2384 if map.pmap != 0:
2385 rsize = int(map.pmap.stats.resident_count)
3e170ce0
A
2386 print "{:<18s} {:<18s} {:<18s} {:>10s} {:>18s} {:>18s}:{:<18s}".format("vm_map","pmap","size","#ents","rsize","start","end")
2387 print "{:#018x} {:#018x} {:#018x} {:>10d} {:>18d} {:#018x}:{:#018x}".format(map,map.pmap,unsigned(map.size),map.hdr.nentries,rsize,map.hdr.links.start,map.hdr.links.end)
fe8ab488
A
2388 vme_list_head = map.hdr.links
2389 vme_ptr_type = GetType('vm_map_entry *')
3e170ce0
A
2390 print "{:<18s} {:>18s}:{:<18s} {:>10s} {:<8s} {:<10s} {:<18s} {:<18s}".format("entry","start","end","#pgs","tag.kmod","prot&flags","object","offset")
2391 last_end = unsigned(map.hdr.links.start)
fe8ab488 2392 for vme in IterateQueue(vme_list_head, vme_ptr_type, "links"):
3e170ce0
A
2393 if unsigned(vme.links.start) != last_end:
2394 print "{:18s} {:#018x}:{:#018x} {:>10d}".format("------------------",last_end,vme.links.start,(unsigned(vme.links.start) - last_end)/page_size)
2395 last_end = unsigned(vme.links.end)
2396 size = unsigned(vme.links.end) - unsigned(vme.links.start)
2397 object = vme.vme_object.vmo_object
2398 if object == 0:
2399 object_str = "{:<#018x}".format(object)
2400 elif vme.is_sub_map:
2401 if object == kern.globals.bufferhdr_map:
2402 object_str = "BUFFERHDR_MAP"
2403 elif object == kern.globals.mb_map:
2404 object_str = "MB_MAP"
2405 elif object == kern.globals.bsd_pageable_map:
2406 object_str = "BSD_PAGEABLE_MAP"
2407 elif object == kern.globals.ipc_kernel_map:
2408 object_str = "IPC_KERNEL_MAP"
2409 elif object == kern.globals.ipc_kernel_copy_map:
2410 object_str = "IPC_KERNEL_COPY_MAP"
2411 elif object == kern.globals.kalloc_map:
2412 object_str = "KALLOC_MAP"
2413 elif object == kern.globals.zone_map:
2414 object_str = "ZONE_MAP"
2415 elif hasattr(kern.globals, 'gzalloc_map') and object == kern.globals.gzalloc_map:
2416 object_str = "GZALLOC_MAP"
2417 elif hasattr(kern.globals, 'g_kext_map') and object == kern.globals.g_kext_map:
2418 object_str = "G_KEXT_MAP"
2419 elif hasattr(kern.globals, 'vector_upl_submap') and object == kern.globals.vector_upl_submap:
2420 object_str = "VECTOR_UPL_SUBMAP"
2421 else:
2422 object_str = "submap:{:<#018x}".format(object)
2423 else:
2424 if object == kern.globals.kernel_object:
2425 object_str = "KERNEL_OBJECT"
2426 elif object == kern.globals.vm_submap_object:
2427 object_str = "VM_SUBMAP_OBJECT"
2428 elif object == kern.globals.compressor_object:
2429 object_str = "COMPRESSOR_OBJECT"
2430 else:
2431 object_str = "{:<#018x}".format(object)
2432 offset = unsigned(vme.vme_offset) & ~0xFFF
2433 tag = unsigned(vme.vme_offset & 0xFFF)
fe8ab488
A
2434 vme_flags = ""
2435 if vme.is_sub_map:
2436 vme_flags += "s"
3e170ce0
A
2437 if vme.needs_copy:
2438 vme_flags += "n"
2439 if vme.is_sub_map and vme.use_pmap:
2440 vme_flags += "p"
2441 tagstr = ""
2442 if map.pmap == kern.globals.kernel_pmap:
2443 xsite = Cast(kern.globals.vm_allocation_sites[tag],'OSKextAccount *')
2444 if xsite and xsite.site.flags & 2:
2445 tagstr = ".{:<3d}".format(xsite.loadTag)
2446 print "{:#018x} {:#018x}:{:#018x} {:>10d} {:>3d}{:<4s} {:1d}{:1d}{:<8s} {:<18s} {:<#18x}".format(vme,vme.links.start,vme.links.end,(unsigned(vme.links.end)-unsigned(vme.links.start))/page_size,tag,tagstr,vme.protection,vme.max_protection,vme_flags,object_str,offset)
2447 if (show_pager_info or show_all_shadows) and vme.is_sub_map == 0 and vme.vme_object.vmo_object != 0:
2448 object = vme.vme_object.vmo_object
fe8ab488
A
2449 else:
2450 object = 0
2451 depth = 0
fe8ab488
A
2452 while object != 0:
2453 depth += 1
2454 if show_all_shadows == False and depth != 1 and object.shadow != 0:
2455 offset += unsigned(object.vo_un2.vou_shadow_offset)
2456 object = object.shadow
2457 continue
2458 if object.copy_strategy == 0:
2459 copy_strategy="N"
2460 elif object.copy_strategy == 2:
2461 copy_strategy="D"
2462 elif object.copy_strategy == 4:
2463 copy_strategy="S"
2464 else:
2465 copy_strategy=str(object.copy_strategy)
2466 if object.internal:
2467 internal = "internal"
2468 else:
2469 internal = "external"
2470 pager_string = ""
3e170ce0
A
2471 pager = object.pager
2472 if show_pager_info and pager != 0:
fe8ab488
A
2473 if object.internal:
2474 pager_string = "-> compressed:{:d}".format(GetCompressedPagesForObject(object))
3e170ce0
A
2475 elif unsigned(pager.mo_pager_ops) == vnode_pager_ops_addr:
2476 vnode_pager = Cast(pager,'vnode_pager *')
2477 pager_string = "-> " + GetVnodePath(vnode_pager.vnode_handle)
fe8ab488 2478 else:
3e170ce0
A
2479 pager_string = "-> {:s}:{:#018x}".format(pager.mo_pager_ops.memory_object_pager_name, pager.mo_pager_ops)
2480 print "{:>18d} {:#018x}:{:#018x} {:#018x} ref:{:<6d} ts:{:1d} strat:{:1s} {:s} ({:d} {:d} {:d}) {:s}".format(depth,offset,offset+size,object,object.ref_count,object.true_share,copy_strategy,internal,unsigned(object.vo_un1.vou_size)/page_size,object.resident_page_count,object.wired_page_count,pager_string)
2481# print " #{:<5d} obj {:#018x} ref:{:<6d} ts:{:1d} strat:{:1s} {:s} size:{:<10d} wired:{:<10d} resident:{:<10d} reusable:{:<10d}".format(depth,object,object.ref_count,object.true_share,copy_strategy,internal,object.vo_un1.vou_size/page_size,object.wired_page_count,object.resident_page_count,object.reusable_page_count)
fe8ab488
A
2482 offset += unsigned(object.vo_un2.vou_shadow_offset)
2483 object = object.shadow
3e170ce0
A
2484 if unsigned(map.hdr.links.end) > last_end:
2485 print "{:18s} {:#018x}:{:#018x} {:>10d}".format("------------------",last_end,map.hdr.links.end,(unsigned(map.hdr.links.end) - last_end)/page_size)
fe8ab488
A
2486 return None
2487
3e170ce0
A
2488def CountMapTags(map, tagcounts, slow):
2489 page_size = unsigned(kern.globals.page_size)
2490 vme_list_head = map.hdr.links
2491 vme_ptr_type = GetType('vm_map_entry *')
2492 for vme in IterateQueue(vme_list_head, vme_ptr_type, "links"):
2493 object = vme.vme_object.vmo_object
2494 tag = vme.vme_offset & 0xFFF
2495 if object == kern.globals.kernel_object:
2496 count = 0
2497 if not slow:
2498 count = unsigned(vme.links.end - vme.links.start) / page_size
2499 else:
2500 addr = unsigned(vme.links.start)
2501 while addr < unsigned(vme.links.end):
2502 hash_id = _calc_vm_page_hash(object, addr)
2503 page_list = kern.globals.vm_page_buckets[hash_id].page_list
2504 page = _vm_page_unpack_ptr(page_list)
2505 while (page != 0):
2506 vmpage = kern.GetValueFromAddress(page, 'vm_page_t')
2507 if (addr == unsigned(vmpage.offset)) and (object == vmpage.object):
2508 if (not vmpage.local) and (vmpage.wire_count > 0):
2509 count += 1
2510 break
2511 page = _vm_page_unpack_ptr(vmpage.next_m)
2512 addr += page_size
2513 tagcounts[tag] += count
2514 elif vme.is_sub_map:
2515 CountMapTags(Cast(object,'vm_map_t'), tagcounts, slow)
2516 return None
2517
2518def CountWiredObject(object, tagcounts):
2519 tagcounts[unsigned(object.wire_tag)] += object.wired_page_count
2520 return None
2521
2522def CountWiredPurgeableGroup(qhead, tagcounts):
2523 for object in IterateQueue(qhead, 'struct vm_object *', 'objq'):
2524 CountWiredObject(object, tagcounts)
2525 return None
2526
2527def CountWiredPurgeableQueue(qhead, tagcounts):
2528 CountWiredPurgeableGroup(qhead.objq[0], tagcounts)
2529 CountWiredPurgeableGroup(qhead.objq[1], tagcounts)
2530 CountWiredPurgeableGroup(qhead.objq[2], tagcounts)
2531 CountWiredPurgeableGroup(qhead.objq[3], tagcounts)
2532 CountWiredPurgeableGroup(qhead.objq[4], tagcounts)
2533 CountWiredPurgeableGroup(qhead.objq[5], tagcounts)
2534 CountWiredPurgeableGroup(qhead.objq[6], tagcounts)
2535 CountWiredPurgeableGroup(qhead.objq[7], tagcounts)
2536
2537def GetKmodIDName(kmod_id):
2538 kmod_val = kern.globals.kmod
2539 for kmod in IterateLinkedList(kmod_val, 'next'):
2540 if (kmod.id == kmod_id):
2541 return "{:<50s}".format(kmod.name)
2542 return "??"
2543
2544def GetVMKernName(tag):
2545 if 1 == tag:
2546 return "VM_KERN_MEMORY_OSFMK"
2547 elif 2 == tag:
2548 return "VM_KERN_MEMORY_BSD"
2549 elif 3 == tag:
2550 return "VM_KERN_MEMORY_IOKIT"
2551 elif 4 == tag:
2552 return "VM_KERN_MEMORY_LIBKERN"
2553 elif 5 == tag:
2554 return "VM_KERN_MEMORY_OSKEXT"
2555 elif 6 == tag:
2556 return "VM_KERN_MEMORY_KEXT"
2557 elif 7 == tag:
2558 return "VM_KERN_MEMORY_IPC"
2559 elif 8 == tag:
2560 return "VM_KERN_MEMORY_STACK"
2561 elif 9 == tag:
2562 return "VM_KERN_MEMORY_CPU"
2563 elif 10 == tag:
2564 return "VM_KERN_MEMORY_PMAP"
2565 elif 11 == tag:
2566 return "VM_KERN_MEMORY_PTE"
2567 elif 12 == tag:
2568 return "VM_KERN_MEMORY_ZONE"
2569 elif 13 == tag:
2570 return "VM_KERN_MEMORY_KALLOC"
2571 elif 14 == tag:
2572 return "VM_KERN_MEMORY_COMPRESSOR"
2573 elif 15 == tag:
2574 return "VM_KERN_MEMORY_COMPRESSED_DATA"
2575 elif 16 == tag:
2576 return "VM_KERN_MEMORY_PHANTOM_CACHE"
2577 elif 17 == tag:
2578 return "VM_KERN_MEMORY_WAITQ"
2579 elif 18 == tag:
2580 return "VM_KERN_MEMORY_DIAG"
2581 elif 19 == tag:
2582 return "VM_KERN_MEMORY_LOG"
2583 elif 20 == tag:
2584 return "VM_KERN_MEMORY_FILE"
2585 elif 21 == tag:
2586 return "VM_KERN_MEMORY_MBUF"
2587 elif 22 == tag:
2588 return "VM_KERN_MEMORY_UBC"
2589 elif 23 == tag:
2590 return "VM_KERN_MEMORY_SECURITY"
2591 elif 24 == tag:
2592 return "VM_KERN_MEMORY_MLOCK"
2593 return "??"
2594
2595
2596@lldb_command("showvmtags", "S")
2597def showvmtags(cmd_args=None, cmd_options={}):
2598 """Routine to print out info about kernel wired page allocations
2599 usage: showvmtags
2600 iterates kernel map and vm objects totaling allocations by tag.
2601 usage: showvmtags -S
2602 also iterates kernel object pages individually - slow.
2603 """
2604 slow = False
2605 if "-S" in cmd_options:
2606 slow = True
2607 page_size = unsigned(kern.globals.page_size)
2608 tagcounts = []
2609 for tag in range(256):
2610 tagcounts.append(0)
2611
2612 queue_head = kern.globals.vm_objects_wired
2613 for object in IterateQueue(queue_head, 'struct vm_object *', 'objq'):
2614 CountWiredObject(object, tagcounts)
2615
2616 queue_head = kern.globals.purgeable_nonvolatile_queue
2617 for object in IterateQueue(queue_head, 'struct vm_object *', 'objq'):
2618 CountWiredObject(object, tagcounts)
2619
2620 purgeable_queues = kern.globals.purgeable_queues
2621 CountWiredPurgeableQueue(purgeable_queues[0], tagcounts)
2622 CountWiredPurgeableQueue(purgeable_queues[1], tagcounts)
2623 CountWiredPurgeableQueue(purgeable_queues[2], tagcounts)
2624
2625 CountMapTags(kern.globals.kernel_map, tagcounts, slow)
2626
2627 total = 0
2628 print " {:<8s} {:>7s} {:<50s}".format("tag.kmod","size","name")
2629 for tag in range(256):
2630 if tagcounts[tag]:
2631 total += tagcounts[tag]
2632 tagstr = ""
2633 sitestr = ""
2634 if (tag <= 24):
2635 sitestr = GetVMKernName(tag)
2636 else:
2637 site = kern.globals.vm_allocation_sites[tag]
2638 if site:
2639 if site.flags & 2:
2640 xsite = Cast(site,'OSKextAccount *')
2641 tagstr = ".{:<3d}".format(xsite.loadTag)
2642 sitestr = GetKmodIDName(xsite.loadTag)
2643 else:
2644 sitestr = kern.Symbolicate(site)
2645 print " {:>3d}{:<4s} {:>7d}K {:<50s}".format(tag,tagstr,tagcounts[tag]*page_size / 1024,sitestr)
2646 print "Total: {:>7d}K".format(total*page_size / 1024)
2647 return None
2648
2649
fe8ab488
A
2650def FindVMEntriesForVnode(task, vn):
2651 """ returns an array of vme that have the vnode set to defined vnode
2652 each entry in array is of format (vme, start_addr, end_address, protection)
2653 """
2654 retval = []
2655 vmmap = task.map
2656 pmap = vmmap.pmap
2657 pager_ops_addr = unsigned(addressof(kern.globals.vnode_pager_ops))
2658 debuglog("pager_ops_addr %s" % hex(pager_ops_addr))
2659
2660 if unsigned(pmap) == 0:
2661 return retval
2662 vme_list_head = vmmap.hdr.links
2663 vme_ptr_type = gettype('vm_map_entry *')
2664 for vme in IterateQueue(vme_list_head, vme_ptr_type, 'links'):
2665 #print vme
3e170ce0
A
2666 if unsigned(vme.is_sub_map) == 0 and unsigned(vme.vme_object.vmo_object) != 0:
2667 obj = vme.vme_object.vmo_object
fe8ab488
A
2668 else:
2669 continue
2670
2671 while obj != 0:
2672 if obj.pager != 0:
2673 if obj.internal:
2674 pass
2675 else:
2676 vn_pager = Cast(obj.pager, 'vnode_pager *')
2677 if unsigned(vn_pager.pager_ops) == pager_ops_addr and unsigned(vn_pager.vnode_handle) == unsigned(vn):
2678 retval.append((vme, unsigned(vme.links.start), unsigned(vme.links.end), unsigned(vme.protection)))
2679 obj = obj.shadow
2680 return retval
2681
2682@lldb_command('showtaskloadinfo')
2683def ShowTaskLoadInfo(cmd_args=None, cmd_options={}):
2684 """ Print the load address and uuid for the process
2685 Usage: (lldb)showtaskloadinfo <task_t>
2686 """
2687 if not cmd_args:
2688 raise ArgumentError("Insufficient arguments")
2689 t = kern.GetValueFromAddress(cmd_args[0], 'struct task *')
2690 print_format = "0x{0:x} - 0x{1:x} {2: <50s} (??? - ???) <{3: <36s}> {4: <50s}"
2691 p = Cast(t.bsd_info, 'struct proc *')
2692 uuid = p.p_uuid
2693 uuid_out_string = "{a[0]:02X}{a[1]:02X}{a[2]:02X}{a[3]:02X}-{a[4]:02X}{a[5]:02X}-{a[6]:02X}{a[7]:02X}-{a[8]:02X}{a[9]:02X}-{a[10]:02X}{a[11]:02X}{a[12]:02X}{a[13]:02X}{a[14]:02X}{a[15]:02X}".format(a=uuid)
2694 filepath = GetVnodePath(p.p_textvp)
2695 libname = filepath.split('/')[-1]
2696 #print "uuid: %s file: %s" % (uuid_out_string, filepath)
2697 mappings = FindVMEntriesForVnode(t, p.p_textvp)
2698 load_addr = 0
2699 end_addr = 0
2700 for m in mappings:
2701 if m[3] == 5:
2702 load_addr = m[1]
2703 end_addr = m[2]
2704 #print "Load address: %s" % hex(m[1])
2705 print print_format.format(load_addr, end_addr, libname, uuid_out_string, filepath)
3e170ce0
A
2706 return None
2707
2708@header("{0: <20s} {1: <20s} {2: <20s}".format("vm_page_t", "offset", "object"))
2709@lldb_command('vmpagelookup')
2710def VMPageLookup(cmd_args=None):
2711 """ Print the pages in the page bucket corresponding to the provided object and offset.
2712 Usage: (lldb)vmpagelookup <vm_object_t> <vm_offset_t>
2713 """
2714 if cmd_args == None or len(cmd_args) < 2:
2715 raise ArgumentError("Please specify an object and offset.")
2716 format_string = "{0: <#020x} {1: <#020x} {2: <#020x}\n"
2717
2718 obj = kern.GetValueFromAddress(cmd_args[0],'unsigned long long')
2719 off = kern.GetValueFromAddress(cmd_args[1],'unsigned long long')
2720
2721 hash_id = _calc_vm_page_hash(obj, off)
2722
2723 page_list = kern.globals.vm_page_buckets[hash_id].page_list
2724 print("hash_id: 0x%x page_list: 0x%x\n" % (unsigned(hash_id), unsigned(page_list)))
2725
2726 print VMPageLookup.header
2727 page = _vm_page_unpack_ptr(page_list)
2728 while (page != 0) :
2729 pg_t = kern.GetValueFromAddress(page, 'vm_page_t')
2730 print format_string.format(page, pg_t.offset, pg_t.object)
2731 page = _vm_page_unpack_ptr(pg_t.next_m)
2732
2733def _vm_page_unpack_ptr(page):
2734 if kern.ptrsize == 4 :
2735 return page
2736
2737 if page == 0 :
2738 return page
2739
2740 min_addr = kern.globals.vm_min_kernel_and_kext_address
2741 #INTEL - min_addr = 0xffffff7f80000000
2742 #ARM - min_addr = 0x80000000
2743 #ARM64 - min_addr = 0xffffff8000000000
2744 return ((page << 6) + min_addr)
2745
2746@lldb_command('calcvmpagehash')
2747def CalcVMPageHash(cmd_args=None):
2748 """ Get the page bucket corresponding to the provided object and offset.
2749 Usage: (lldb)calcvmpagehash <vm_object_t> <vm_offset_t>
2750 """
2751 if cmd_args == None or len(cmd_args) < 2:
2752 raise ArgumentError("Please specify an object and offset.")
2753
2754 obj = kern.GetValueFromAddress(cmd_args[0],'unsigned long long')
2755 off = kern.GetValueFromAddress(cmd_args[1],'unsigned long long')
2756
2757 hash_id = _calc_vm_page_hash(obj, off)
2758
2759 print("hash_id: 0x%x page_list: 0x%x\n" % (unsigned(hash_id), unsigned(kern.globals.vm_page_buckets[hash_id].page_list)))
2760 return None
2761
2762def _calc_vm_page_hash(obj, off):
2763 bucket_hash = (int) (kern.globals.vm_page_bucket_hash)
2764 hash_mask = (int) (kern.globals.vm_page_hash_mask)
2765
2766 one = (obj * bucket_hash) & 0xFFFFFFFF
2767 two = off >> unsigned(kern.globals.page_shift)
2768 three = two ^ bucket_hash
2769 four = one + three
2770 hash_id = four & hash_mask
2771
2772 return hash_id
2773
2774@header("{0: <10s} of {1: <10s} {2: <20s} {3: <20s} {4: <20s} {5: <10s} {6: <5s}\t {7: <28s}\t{8: <50s}".format("index", "total", "vm_page_t", "offset", "next", "phys_page", "wire#", "first bitfield", "second bitfield"))
2775@lldb_command('vmobjectwalkpages', 'SBNQP:')
2776def VMObjectWalkPages(cmd_args=None, cmd_options={}):
2777 """ Print the resident pages contained in the provided object. If a vm_page_t is provided as well, we
2778 specifically look for this page, highlighting it in the output or noting if it was not found. For
2779 each page, we confirm that it points to the object. We also keep track of the number of pages we
2780 see and compare this to the object's resident page count field.
2781 Usage:
2782 vmobjectwalkpages <vm_object_t> : Walk and print all the pages for a given object (up to 4K pages by default)
2783 vmobjectwalkpages <vm_object_t> -B : Walk and print all the pages for a given object (up to 4K pages by default), traversing the memq backwards
2784 vmobjectwalkpages <vm_object_t> -N : Walk and print all the pages for a given object, ignore the page limit
2785 vmobjectwalkpages <vm_object_t> -Q : Walk all pages for a given object, looking for known signs of corruption (i.e. inactive and active both being set for a page)
2786 vmobjectwalkpages <vm_object_t> -P <vm_page_t> : Walk all the pages for a given object, annotate the specified page in the output with ***
2787 vmobjectwalkpages <vm_object_t> -P <vm_page_t> -S : Walk all the pages for a given object, stopping when we find the specified page
2788
2789 """
2790
2791 if (cmd_args == None or len(cmd_args) < 1):
2792 raise ArgumentError("Please specify at minimum a vm_object_t and optionally a vm_page_t")
2793
2794 out_string = ""
2795
2796 obj = kern.GetValueFromAddress(cmd_args[0], 'vm_object_t')
2797
2798 page = 0
2799 if "-P" in cmd_options:
2800 page = kern.GetValueFromAddress(cmd_options['-P'], 'vm_page_t')
2801
2802 stop = 0
2803 if "-S" in cmd_options:
2804 if page == 0:
2805 raise ArgumentError("-S can only be passed when a page is specified with -P")
2806 stop = 1
2807
2808 walk_backwards = False
2809 if "-B" in cmd_options:
2810 walk_backwards = True
2811
2812 quiet_mode = False
2813 if "-Q" in cmd_options:
2814 quiet_mode = True
2815
2816 if not quiet_mode:
2817 print VMObjectWalkPages.header
2818 format_string = "{0: <#10d} of {1: <#10d} {2: <#020x} {3: <#020x} {4: <#020x} {5: <#010x} {6: <#05d}\t"
2819 first_bitfield_format_string = "{0: <#1d}:{1: <#1d}:{2: <#1d}:{3: <#1d}:{4: <#1d}:{5: <#1d}:{6: <#1d}:"
2820 first_bitfield_format_string += "{7: <#1d}:{8: <#1d}:{9: <#1d}:{10: <#1d}:{11: <#1d}:{12: <#1d}"
2821 second_bitfield_format_string = first_bitfield_format_string
2822 second_bitfield_format_string += ":{13: <#1d}:{14: <#1d}:{15: <#1d}:{16: <#1d}:{17: <#1d}:{18: <#1d}:{19: <#1d}:"
2823 second_bitfield_format_string += "{20: <#1d}:{21: <#1d}:{22: <#1d}:{23: <#1d}:{24: <#1d}:{25: <#1d}:{26: <#1d}\n"
2824 first_bitfield_format_string += "\t"
2825
2826 limit = 4096 #arbitrary limit of number of pages to walk
2827 ignore_limit = 0
2828 if "-N" in cmd_options:
2829 ignore_limit = 1
2830
2831 page_count = 0
2832 res_page_count = unsigned(obj.resident_page_count)
2833 page_found = False
2834 pages_seen = set()
2835
2836 for vmp in IterateQueue(obj.memq, "vm_page_t", "listq", walk_backwards):
2837 page_count += 1
2838 out_string = ""
2839 if (page != 0 and not(page_found) and vmp == page):
2840 out_string += "******"
2841 page_found = True
2842
2843 if page != 0 or quiet_mode:
2844 if (page_count % 1000) == 0:
2845 print "traversed %d pages ...\n" % (page_count)
2846 else:
2847 out_string += format_string.format(page_count, res_page_count, vmp, vmp.offset, vmp.listq.next, vmp.phys_page, vmp.wire_count)
2848 out_string += first_bitfield_format_string.format(vmp.active, vmp.inactive, vmp.clean_queue, vmp.local, vmp.speculative,
2849 vmp.throttled, vmp.free, vmp.pageout_queue, vmp.laundry, vmp.reference,
2850 vmp.gobbled, vmp.private, vmp.no_cache)
2851
2852 out_string += second_bitfield_format_string.format(vmp.busy, vmp.wanted, vmp.tabled, vmp.hashed, vmp.fictitious, vmp.clustered,
2853 vmp.clustered, vmp.pmapped, vmp.xpmapped, vmp.wpmapped, vmp.pageout, vmp.absent,
2854 vmp.error, vmp.dirty, vmp.cleaning, vmp.precious, vmp.precious, vmp.overwriting,
2855 vmp.restart, vmp.unusual, vmp.encrypted, vmp.encrypted, vmp.encrypted_cleaning,
2856 vmp.cs_validated, vmp.cs_tainted, vmp.cs_nx, vmp.reusable, vmp.lopage, vmp.slid, vmp.compressor,
2857 vmp.written_by_kernel)
2858
2859 if (vmp in pages_seen):
2860 print out_string + "cycle detected! we've seen vm_page_t: " + "{0: <#020x}".format(unsigned(vmp)) + " twice. stopping...\n"
2861 return
2862
2863 if (vmp.object != obj):
2864 print out_string + " vm_page_t: " + "{0: <#020x}".format(unsigned(vmp)) + " points to different vm_object_t: " + "{0: <#020x}".format(unsigned(vmp.object))
2865 return
2866
2867 if (not vmp.local) and (vmp.wire_count > 0):
2868 if (vmp.active or vmp.inactive or vmp.speculative or vmp.throttled or vmp.pageout_queue):
2869 print out_string + " wired page with wrong page queue attributes\n"
2870 print "vm_page_t: " + "{0: <#020x}".format(unsigned(vmp)) + " active: %d inactive: %d speculative: %d throttled %d pageout_queue: %d\n" % (vmp.active,
2871 vmp.inactive, vmp.speculative, vmp.throttled, vmp.pageout_queue)
2872 print "stopping...\n"
2873 return
2874
2875 if ((vmp.free + vmp.active + vmp.inactive + vmp.speculative + vmp.throttled + vmp.pageout_queue) > 1):
2876 print out_string + " more than one pageout queue bit set active\n"
2877 print "vm_page_t: " + "{0: <#020x}".format(unsigned(vmp)) + " free: %d active: %d inactive: %d speculative: %d throttled: %d pageout_queue: %d\n" % (vmp.free,
2878 vmp.active, vmp.inactive, vmp.speculative, vmp.throttled, vmp.pageout_queue)
2879 print "stopping...\n"
2880 return
2881
2882 if ((vmp.__unused_pageq_bits != 0) or (vmp.__unused_object_bits != 0)):
2883 print out_string + " unused bits not zero for vm_page_t: " + "{0: <#020x}".format(unsigned(vmp)) + " unused__pageq_bits: %d unused_object_bits : %d\n" % (vmp.__unused_pageq_bits,
2884 vmp.__unused_object_bits)
2885 print "stopping...\n"
2886 return
2887
2888 pages_seen.add(vmp)
2889
2890 if False:
2891 hash_id = _calc_vm_page_hash(obj, vmp.offset)
2892 hash_page_list = kern.globals.vm_page_buckets[hash_id].page_list
2893 hash_page = _vm_page_unpack_ptr(hash_page_list)
2894 hash_page_t = 0
2895
2896 while (hash_page != 0):
2897 hash_page_t = kern.GetValueFromAddress(hash_page, 'vm_page_t')
2898 if hash_page_t == vmp:
2899 break
2900 hash_page = _vm_page_unpack_ptr(hash_page_t.next_m)
2901
2902 if (unsigned(vmp) != unsigned(hash_page_t)):
2903 print out_string + "unable to find page: " + "{0: <#020x}".format(unsigned(vmp)) + " from object in kernel page bucket list\n"
2904 print lldb_run_command("vm_page_info %s 0x%x" % (cmd_args[0], unsigned(vmp.offset)))
2905 return
2906
2907 if (page_count >= limit and not(ignore_limit)):
2908 print out_string + "Limit reached (%d pages), stopping..." % (limit)
2909 return
2910
2911 print out_string
2912
2913 if page_found and stop:
2914 print("Object reports resident page count of: %d we stopped after traversing %d and finding the requested page.\n" % (unsigned(obj.res_page_count), unsigned(page_count)))
2915 return
2916
2917 if (page != 0):
2918 print("page found? : %s\n" % page_found)
2919
2920 print("Object reports resident page count of %d, we saw %d pages when we walked the resident list.\n" % (unsigned(obj.resident_page_count), unsigned(page_count)))
2921
2922
2923@lldb_command("show_all_apple_protect_pagers")
2924def ShowAllAppleProtectPagers(cmd_args=None):
2925 """Routine to print all apple_protect pagers
2926 usage: show_all_apple_protect_pagers
2927 """
2928 print "{:>3s} {:<3s} {:<18s} {:>5s} {:>5s} {:>6s} {:<18s} {:<18s} {:<18s} {:<18s} {:<18s} {:<18s}\n".format("#", "#", "pager", "refs", "ready", "mapped", "mo_control", "object", "offset", "crypto_offset", "crypto_start", "crypto_end")
2929 qhead = kern.globals.apple_protect_pager_queue
2930 qtype = GetType('apple_protect_pager *')
2931 qcnt = kern.globals.apple_protect_pager_count
2932 idx = 0
2933 for pager in IterateQueue(qhead, qtype, "pager_queue"):
2934 idx = idx + 1
2935 show_apple_protect_pager(pager, qcnt, idx)
2936
2937@lldb_command("show_apple_protect_pager")
2938def ShowAppleProtectPager(cmd_args=None):
2939 """Routine to print out info about an apple_protect pager
2940 usage: show_apple_protect_pager <pager>
2941 """
2942 if cmd_args == None or len(cmd_args) < 1:
2943 print "Invalid argument.", ShowMap.__doc__
2944 return
2945 pager = kern.GetValueFromAddress(cmd_ars[0], 'apple_protect_pager_t')
2946 show_apple_protect_pager(pager, 1, 1)
2947
2948def show_apple_protect_pager(pager, qcnt, idx):
2949 object = pager.backing_object
2950 shadow = object.shadow
2951 while shadow != 0:
2952 object = shadow
2953 shadow = object.shadow
2954 vnode_pager = Cast(object.pager,'vnode_pager *')
2955 filename = GetVnodePath(vnode_pager.vnode_handle)
2956 print "{:>3}/{:<3d} {:#018x} {:>5d} {:>5d} {:>6d} {:#018x} {:#018x} {:#018x} {:#018x} {:#018x} {:#018x}\n\tcrypt_info:{:#018x} <decrypt:{:#018x} end:{:#018x} ops:{:#018x} refs:{:<d}>\n\tvnode:{:#018x} {:s}\n".format(idx, qcnt, pager, pager.ref_count, pager.is_ready, pager.is_mapped, pager.pager_control, pager.backing_object, pager.backing_offset, pager.crypto_backing_offset, pager.crypto_start, pager.crypto_end, pager.crypt_info, pager.crypt_info.page_decrypt, pager.crypt_info.crypt_end, pager.crypt_info.crypt_ops, pager.crypt_info.crypt_refcnt, vnode_pager.vnode_handle, filename)