2 """ Please make sure you read the README file COMPLETELY BEFORE reading anything below.
3 It is very critical that you read coding guidelines in Section E in README file.
13 @lldb_command('memstats')
14 def 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.
18 print "memorystatus_level: {: >10d}".format(kern
.globals.memorystatus_level
)
22 print "memorystatus_available_pages: {: >10d}".format(kern
.globals.memorystatus_available_pages
)
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
)
36 @xnudebug_test('test_memstats')
37 def TestMemstats(kernel_target
, config
, lldb_obj
, isConnected
):
38 """ Test the functionality of memstats command
44 print "Target is not connected. Cannot test memstats"
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 :
56 # Macro: showmemorystatus
57 def 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
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
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'))
73 def 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
79 task_val
= Cast(proc_val
.task
, 'task *')
80 task_ledgerp
= task_val
.ledger
82 task_physmem_footprint_ledger_entry
= task_ledgerp
.l_entries
[kern
.globals.task_ledgers
.phys_mem
]
83 task_iokit_footprint_ledger_entry
= task_ledgerp
.l_entries
[kern
.globals.task_ledgers
.iokit_mapped
]
84 task_phys_footprint_ledger_entry
= task_ledgerp
.l_entries
[kern
.globals.task_ledgers
.phys_footprint
]
85 page_size
= kern
.globals.page_size
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
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
)
101 out_str
+= "{: ^12s}".format('-')
102 out_str
+= "{: 8d} {: <20s}\n".format(phys_footprint_limit
, proc_val
.p_comm
)
105 @lldb_command('showmemorystatus')
106 def ShowMemoryStatus(cmd_args
=None):
107 """ Routine to display each entry in jetsam list with a summary of pressure statistics
108 Usage: showmemorystatus
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
126 # EndMacro: showmemorystatus
130 @lldb_type_summary(['zone','zone_t'])
131 @header("{:^18s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s}({:>6s} {:>6s} {:>6s}) {:^14s} {:<20s}".format(
132 'ZONE', 'TOT_SZ', 'PAGE_COUNT', 'ALLOC_ELTS', 'FREE_ELTS', 'FREE_SZ', 'ELT_SZ', 'ALLOC', 'ELTS', 'PGS', 'SLK', 'FLAGS', 'NAME'))
133 def GetZoneSummary(zone
):
134 """ Summarize a zone with important information. See help zprint for description of each field
136 zone: value - obj representing a zone in kernel
138 str - summary of the zone
141 format_string
= '{:#018x} {:10d} {:10d} {:10d} {:10d} {:10d} {:10d} {:10d} {:6d} {:6d} {:6d} {markings} {name:s} '
144 free_elements
= (zone
.cur_size
/ zone
.elem_size
) - zone
.count
145 free_size
= free_elements
* zone
.elem_size
147 alloc_count
= zone
.alloc_size
/ zone
.elem_size
148 alloc_pages
= zone
.alloc_size
/ pagesize
149 alloc_slack
= zone
.alloc_size
% zone
.elem_size
151 ["collectable", "C"],
154 ["caller_acct", "@"],
155 ["exhaustible", "H"],
156 ["allows_foreign", "F"],
157 ["async_prio_refill", "R"],
160 ["doing_alloc", "A"],
164 if kern
.arch
== 'x86_64':
165 marks
.append(["gzalloc_exempt", "M"])
166 marks
.append(["alignment_required", "N"])
170 if zone
.__getattr
__(mark
[0]) :
174 out_string
+= format_string
.format(zone
, zone
.cur_size
, zone
.page_count
,
175 zone
.count
, free_elements
, free_size
,
176 zone
.elem_size
, zone
.alloc_size
, alloc_count
,
177 alloc_pages
, alloc_slack
, name
= zone
.zone_name
, markings
=markings
)
179 if zone
.exhaustible
:
180 out_string
+= "(max: {:d})".format(zone
.max_size
)
184 @lldb_command('zprint')
185 def Zprint(cmd_args
=None):
186 """ Routine to print a summary listing of all the kernel zones
187 All columns are printed in decimal
191 $ - not encrypted during hibernation
192 @ - allocs and frees are accounted to caller process for KPRVT
194 F - allows foreign memory (memory not allocated from zone_map)
195 M - gzalloc will avoid monitoring this zone
196 R - will be refilled when below low water mark
197 O - does not allow refill callout to fill zone on noblock allocation
198 N - zone requires alignment (avoids padding this zone for debugging)
199 A - currently trying to allocate more backing memory from kernel_memory_allocate
200 W - another thread is waiting for more memory
201 L - zone is being monitored by zleaks
202 G - currently running GC
205 print GetZoneSummary
.header
206 for zval
in kern
.zones
:
207 print GetZoneSummary(zval
)
209 @xnudebug_test('test_zprint')
210 def TestZprint(kernel_target
, config
, lldb_obj
, isConnected
):
211 """ Test the functionality of zprint command
217 print "Target is not connected. Cannot test memstats"
219 res
= lldb
.SBCommandReturnObject()
220 lldb_obj
.debugger
.GetCommandInterpreter().HandleCommand("zprint", res
)
221 result
= res
.GetOutput()
222 if len(result
.split("\n")) > 2:
230 # Macro: showzfreelist
232 def ShowZfreeListHeader(zone
):
233 """ Helper routine to print a header for zone freelist.
234 (Since the freelist does not have a custom type, this is not defined as a Type Summary).
236 zone:zone_t - Zone object to print header info
241 scaled_factor
= (unsigned(kern
.globals.zp_factor
) +
242 (unsigned(zone
.elem_size
) >> unsigned(kern
.globals.zp_scale
)))
245 out_str
+= "{0: <9s} {1: <12s} {2: <18s} {3: <18s} {4: <6s}\n".format('ELEM_SIZE', 'COUNT', 'NCOOKIE', 'PCOOKIE', 'FACTOR')
246 out_str
+= "{0: <9d} {1: <12d} 0x{2:0>16x} 0x{3:0>16x} {4: <2d}/{5: <2d}\n\n".format(
247 zone
.elem_size
, zone
.count
, kern
.globals.zp_nopoison_cookie
, kern
.globals.zp_poisoned_cookie
, zone
.zp_count
, scaled_factor
)
248 out_str
+= "{0: <7s} {1: <18s} {2: <18s} {3: <18s} {4: <18s} {5: <18s} {6: <14s}\n".format(
249 'NUM', 'ELEM', 'NEXT', 'BACKUP', '^ NCOOKIE', '^ PCOOKIE', 'POISON (PREV)')
252 def ShowZfreeListChain(zone
, zfirst
, zlimit
):
253 """ Helper routine to print a zone free list chain
255 zone: zone_t - Zone object
256 zfirst: void * - A pointer to the first element of the free list chain
257 zlimit: int - Limit for the number of elements to be printed by showzfreelist
261 current
= Cast(zfirst
, 'void *')
262 while ShowZfreeList
.elts_found
< zlimit
:
263 ShowZfreeList
.elts_found
+= 1
264 znext
= dereference(Cast(current
, 'vm_offset_t *'))
265 backup_ptr
= kern
.GetValueFromAddress((unsigned(Cast(current
, 'vm_offset_t')) + unsigned(zone
.elem_size
) - sizeof('vm_offset_t')), 'vm_offset_t *')
266 backup_val
= dereference(backup_ptr
)
267 n_unobfuscated
= (unsigned(backup_val
) ^
unsigned(kern
.globals.zp_nopoison_cookie
))
268 p_unobfuscated
= (unsigned(backup_val
) ^
unsigned(kern
.globals.zp_poisoned_cookie
))
270 if p_unobfuscated
== unsigned(znext
):
271 poison_str
= "P ({0: <d})".format(ShowZfreeList
.elts_found
- ShowZfreeList
.last_poisoned
)
272 ShowZfreeList
.last_poisoned
= ShowZfreeList
.elts_found
274 if n_unobfuscated
!= unsigned(znext
):
275 poison_str
= "INVALID"
276 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(
277 ShowZfreeList
.elts_found
, unsigned(current
), unsigned(znext
), unsigned(backup_val
), n_unobfuscated
, p_unobfuscated
, poison_str
)
278 if unsigned(znext
) == 0:
280 current
= Cast(znext
, 'void *')
282 @static_var('elts_found',0)
283 @static_var('last_poisoned',0)
284 @lldb_command('showzfreelist')
285 def ShowZfreeList(cmd_args
=None):
286 """ Walk the freelist for a zone, printing out the primary and backup next pointers, the poisoning cookies, and the poisoning status of each element.
287 Usage: showzfreelist <zone> [iterations]
289 Will walk up to 50 elements by default, pass a limit in 'iterations' to override.
292 print ShowZfreeList
.__doc
__
294 ShowZfreeList
.elts_found
= 0
295 ShowZfreeList
.last_poisoned
= 0
297 zone
= kern
.GetValueFromAddress(cmd_args
[0], 'struct zone *')
299 if len(cmd_args
) >= 2:
300 zlimit
= ArgumentStringToInt(cmd_args
[1])
301 ShowZfreeListHeader(zone
)
303 if unsigned(zone
.use_page_list
) == 1:
304 if unsigned(zone
.allows_foreign
) == 1:
305 for free_page_meta
in IterateQueue(zone
.pages
.any_free_foreign
, 'struct zone_page_metadata *', 'pages'):
306 if ShowZfreeList
.elts_found
== zlimit
:
308 zfirst
= Cast(free_page_meta
.elements
, 'void *')
309 if unsigned(zfirst
) != 0:
310 ShowZfreeListChain(zone
, zfirst
, zlimit
)
311 for free_page_meta
in IterateQueue(zone
.pages
.intermediate
, 'struct zone_page_metadata *', 'pages'):
312 if ShowZfreeList
.elts_found
== zlimit
:
314 zfirst
= Cast(free_page_meta
.elements
, 'void *')
315 if unsigned(zfirst
) != 0:
316 ShowZfreeListChain(zone
, zfirst
, zlimit
)
317 for free_page_meta
in IterateQueue(zone
.pages
.all_free
, 'struct zone_page_metadata *', 'pages'):
318 if ShowZfreeList
.elts_found
== zlimit
:
320 zfirst
= Cast(free_page_meta
.elements
, 'void *')
321 if unsigned(zfirst
) != 0:
322 ShowZfreeListChain(zone
, zfirst
, zlimit
)
324 zfirst
= Cast(zone
.free_elements
, 'void *')
325 if unsigned(zfirst
) != 0:
326 ShowZfreeListChain(zone
, zfirst
, zlimit
)
328 if ShowZfreeList
.elts_found
== zlimit
:
329 print "Stopped at {0: <d} elements!".format(zlimit
)
331 print "Found {0: <d} elements!".format(ShowZfreeList
.elts_found
)
333 # EndMacro: showzfreelist
337 @lldb_command('zstack')
338 def Zstack(cmd_args
=None):
339 """ 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>.
340 Usage: zstack <index> [<count>]
342 The suggested usage is to look at indexes below zcurrent and look for common stack traces.
343 The stack trace that occurs the most is probably the cause of the leak. Find the pc of the
344 function calling into zalloc and use the countpcs command to find out how often that pc occurs in the log.
345 The pc occuring in a high percentage of records is most likely the source of the leak.
347 The findoldest command is also useful for leak debugging since it identifies the oldest record
348 in the log, which may indicate the leaker.
353 if int(kern
.globals.log_records
) == 0:
354 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
356 if int(kern
.globals.zlog_btlog
) == 0:
357 print "Zone logging enabled, but zone has not been initialized yet."
361 if len(cmd_args
) >= 2:
362 count
= ArgumentStringToInt(cmd_args
[1])
363 zstack_index
= unsigned(cmd_args
[0])
364 while count
and (zstack_index
!= 0xffffff):
365 zstack_record_offset
= zstack_index
* unsigned(kern
.globals.zlog_btlog
.btrecord_size
)
366 zstack_record
= kern
.GetValueFromAddress(unsigned(kern
.globals.zlog_btlog
.btrecords
) + zstack_record_offset
, 'btlog_record_t *')
367 ShowZStackRecord(zstack_record
, zstack_index
)
368 zstack_index
= zstack_record
.next
375 @lldb_command('findoldest')
376 def FindOldest(cmd_args
=None):
377 """ Zone leak debugging: find and print the oldest record in the log.
379 Once it prints a stack trace, find the pc of the caller above all the zalloc, kalloc and
380 IOKit layers. Then use the countpcs command to see how often this caller has allocated
381 memory. A caller with a high percentage of records in the log is probably the leaker.
383 if int(kern
.globals.log_records
) == 0:
384 print FindOldest
.__doc
__
386 if int(kern
.globals.zlog_btlog
) == 0:
387 print "Zone logging enabled, but zone has not been initialized yet."
389 index
= kern
.globals.zlog_btlog
.head
390 if unsigned(index
) != 0xffffff:
391 print "Oldest record is at log index: {0: <d}".format(index
)
394 print "No Records Present"
396 # EndMacro : findoldest
400 @lldb_command('countpcs')
401 def Countpcs(cmd_args
=None):
402 """ Zone leak debugging: search the log and print a count of all log entries that contain the given <pc>
406 This is useful for verifying a suspected <pc> as being the source of
407 the leak. If a high percentage of the log entries contain the given <pc>, then it's most
408 likely the source of the leak. Note that this command can take several minutes to run.
411 print Countpcs
.__doc
__
413 if int(kern
.globals.log_records
) == 0:
414 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
416 if int(kern
.globals.zlog_btlog
) == 0:
417 print "Zone logging enabled, but zone has not been initialized yet."
420 cpcs_index
= unsigned(kern
.globals.zlog_btlog
.head
)
421 target_pc
= unsigned(kern
.GetValueFromAddress(cmd_args
[0], 'void *'))
423 depth
= unsigned(kern
.globals.zlog_btlog
.btrecord_btdepth
)
425 while cpcs_index
!= 0xffffff:
426 cpcs_record_offset
= cpcs_index
* unsigned(kern
.globals.zlog_btlog
.btrecord_size
)
427 cpcs_record
= kern
.GetValueFromAddress(unsigned(kern
.globals.zlog_btlog
.btrecords
) + cpcs_record_offset
, 'btlog_record_t *')
430 frame_pc
= unsigned(cpcs_record
.bt
[frame
])
431 if frame_pc
== target_pc
:
435 cpcs_index
= cpcs_record
.next
436 print "Occured {0: <d} times in log ({1: <d}{2: <s} of records)".format(found
, (found
* 100)/unsigned(kern
.globals.zlog_btlog
.activecount
), '%')
442 @lldb_command('findelem')
443 def FindElem(cmd_args
=None):
444 """ Zone corruption debugging: search the log and print out the stack traces for all log entries that
445 refer to the given zone element.
446 Usage: findelem <elem addr>
448 When the kernel panics due to a corrupted zone element, get the
449 element address and use this command. This will show you the stack traces of all logged zalloc and
450 zfree operations which tells you who touched the element in the recent past. This also makes
451 double-frees readily apparent.
454 print FindElem
.__doc
__
456 if int(kern
.globals.log_records
) == 0:
457 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
459 if int(kern
.globals.zlog_btlog
) == 0:
460 print "Zone logging enabled, but zone has not been initialized yet."
463 target_element
= unsigned(kern
.GetValueFromAddress(cmd_args
[0], 'void *'))
464 index
= unsigned(kern
.globals.zlog_btlog
.head
)
467 while index
!= 0xffffff:
468 findelem_record_offset
= index
* unsigned(kern
.globals.zlog_btlog
.btrecord_size
)
469 findelem_record
= kern
.GetValueFromAddress(unsigned(kern
.globals.zlog_btlog
.btrecords
) + findelem_record_offset
, 'btlog_record_t *')
470 if unsigned(findelem_record
.element
) == target_element
:
472 if int(findelem_record
.operation
) == prev_op
:
473 print "{0: <s} DOUBLE OP! {1: <s}".format(('*' * 8), ('*' * 8))
474 prev_op
= int(findelem_record
.operation
)
475 index
= findelem_record
.next
481 @lldb_command('btlog_find', "AS")
482 def BtlogFind(cmd_args
=None, cmd_options
={}):
483 """ Search the btlog_t for entries corresponding to the given element.
484 Use -A flag to print all entries.
485 Use -S flag to summarize the count of records
486 Usage: btlog_find <btlog_t> <element>
487 Usage: btlog_find <btlog_t> -A
488 Note: Backtraces will be in chronological order, with oldest entries aged out in FIFO order as needed.
491 raise ArgumentError("Need a btlog_t parameter")
492 btlog
= kern
.GetValueFromAddress(cmd_args
[0], 'btlog_t *')
496 target_elem
= 0xffffffff
498 if "-A" in cmd_options
:
501 if not printall
and len(cmd_args
) < 2:
502 raise ArgumentError("<element> is missing in args. Need a search pointer.")
503 target_elem
= unsigned(kern
.GetValueFromAddress(cmd_args
[1], 'void *'))
505 if "-S" in cmd_options
:
508 index
= unsigned(btlog
.head
)
510 record_size
= unsigned(btlog
.btrecord_size
)
512 while index
!= 0xffffff:
513 record_offset
= index
* record_size
514 record
= kern
.GetValueFromAddress(unsigned(btlog
.btrecords
) + record_offset
, 'btlog_record_t *')
515 if printall
or unsigned(record
.element
) == target_elem
:
516 _s
= '{0: <s} {2: <#0x} OP {1: <d} {3: <s}'.format(('-' * 8), record
.operation
, unsigned(record
.element
), ('-' * 8))
517 _s
+= GetBtlogBacktrace(btlog
.btrecord_btdepth
, record
)
519 if _s
not in summary_cache
:
520 summary_cache
[_s
] = 1
522 summary_cache
[_s
] += 1
527 if (progress
% 1000) == 0: print '{0: <d} entries searched!\n'.format(progress
)
528 except ValueError, e
:
532 print "=================== SUMMARY =================="
533 for (k
,v
) in summary_cache
.iteritems():
534 print "Count: %d %s \n " % (v
, k
)
537 #EndMacro: btlog_find
541 @lldb_command('showzalloc')
542 def ShowZalloc(cmd_args
=None):
543 """ Prints a zallocation from the zallocations array based off its index and prints the associated symbolicated backtrace.
544 Usage: showzalloc <index>
547 print ShowZalloc
.__doc
__
549 if unsigned(kern
.globals.zallocations
) == 0:
550 print "zallocations array not initialized!"
552 zallocation
= kern
.globals.zallocations
[ArgumentStringToInt(cmd_args
[0])]
554 ShowZTrace([str(int(zallocation
.za_trace_index
))])
556 #EndMacro: showzalloc
560 @lldb_command('showztrace')
561 def ShowZTrace(cmd_args
=None):
562 """ Prints the backtrace from the ztraces array at index
563 Usage: showztrace <trace index>
566 print ShowZTrace
.__doc
__
568 if unsigned(kern
.globals.ztraces
) == 0:
569 print "ztraces array not initialized!"
571 ztrace_addr
= kern
.globals.ztraces
[ArgumentStringToInt(cmd_args
[0])]
573 ShowZstackTraceHelper(ztrace_addr
.zt_stack
, ztrace_addr
.zt_depth
)
575 #EndMacro: showztrace
577 #Macro: showztraceaddr
579 @lldb_command('showztraceaddr')
580 def ShowZTraceAddr(cmd_args
=None):
581 """ Prints the struct ztrace passed in.
582 Usage: showztraceaddr <trace address>
585 print ShowZTraceAddr
.__doc
__
587 ztrace_ptr
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ztrace *')
588 print dereference(ztrace_ptr
)
589 ShowZstackTraceHelper(ztrace_ptr
.zt_stack
, ztrace_ptr
.zt_depth
)
591 #EndMacro: showztraceaddr
593 #Macro: showzstacktrace
595 @lldb_command('showzstacktrace')
596 def ShowZstackTrace(cmd_args
=None):
597 """ Routine to print a stacktrace stored by OSBacktrace.
598 Usage: showzstacktrace <saved stacktrace> [size]
600 size is optional, defaults to 15.
603 print ShowZstackTrace
.__doc
__
605 void_ptr_type
= gettype('void *')
606 void_double_ptr_type
= void_ptr_type
.GetPointerType()
607 trace
= kern
.GetValueFromAddress(cmd_args
[0], void_double_ptr_type
)
609 if len(cmd_args
) >= 2:
610 trace_size
= ArgumentStringToInt(cmd_args
[1])
611 ShowZstackTraceHelper(trace
, trace_size
)
613 #EndMacro: showzstacktrace
615 def ShowZstackTraceHelper(stack
, depth
):
616 """ Helper routine for printing a zstack.
618 stack: void *[] - An array of pointers representing the Zstack
619 depth: int - The depth of the ztrace stack
624 while trace_current
< depth
:
625 trace_addr
= stack
[trace_current
]
626 symbol_arr
= kern
.SymbolicateFromAddress(unsigned(trace_addr
))
628 symbol_str
= str(symbol_arr
[0].addr
)
631 print '{0: <#x} {1: <s}'.format(trace_addr
, symbol_str
)
634 #Macro: showtopztrace
636 @lldb_command('showtopztrace')
637 def ShowTopZtrace(cmd_args
=None):
638 """ Shows the ztrace with the biggest size.
639 (According to top_ztrace, not by iterating through the hash table)
641 top_trace
= kern
.globals.top_ztrace
642 print 'Index: {0: <d}'.format((unsigned(top_trace
) - unsigned(kern
.globals.ztraces
)) / sizeof('struct ztrace'))
643 print dereference(top_trace
)
644 ShowZstackTraceHelper(top_trace
.zt_stack
, top_trace
.zt_depth
)
646 #EndMacro: showtopztrace
650 @lldb_command('showzallocs')
651 def ShowZallocs(cmd_args
=None):
652 """ Prints all allocations in the zallocations table
654 if unsigned(kern
.globals.zallocations
) == 0:
655 print "zallocations array not initialized!"
657 print '{0: <5s} {1: <18s} {2: <5s} {3: <15s}'.format('INDEX','ADDRESS','TRACE','SIZE')
659 max_zallocation
= unsigned(kern
.globals.zleak_alloc_buckets
)
661 while current_index
< max_zallocation
:
662 current_zalloc
= kern
.globals.zallocations
[current_index
]
663 if int(current_zalloc
.za_element
) != 0:
664 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
))
665 allocation_count
+= 1
667 print 'Total Allocations: {0: <d}'.format(allocation_count
)
669 #EndMacro: showzallocs
671 #Macro: showzallocsfortrace
673 @lldb_command('showzallocsfortrace')
674 def ShowZallocsForTrace(cmd_args
=None):
675 """ Prints all allocations pointing to the passed in trace's index into ztraces by looking through zallocations table
676 Usage: showzallocsfortrace <trace index>
679 print ShowZallocsForTrace
.__doc
__
681 print '{0: <5s} {1: <18s} {2: <15s}'.format('INDEX','ADDRESS','SIZE')
682 target_index
= ArgumentStringToInt(cmd_args
[0])
684 max_zallocation
= unsigned(kern
.globals.zleak_alloc_buckets
)
686 while current_index
< max_zallocation
:
687 current_zalloc
= kern
.globals.zallocations
[current_index
]
688 if unsigned(current_zalloc
.za_element
) != 0 and (unsigned(current_zalloc
.za_trace_index
) == unsigned(target_index
)):
689 print '{0: <5d} {1: <#018x} {2: <6d}'.format(current_index
, current_zalloc
.za_element
, current_zalloc
.za_size
)
690 allocation_count
+= 1
692 print 'Total Allocations: {0: <d}'.format(allocation_count
)
694 #EndMacro: showzallocsfortrace
698 @lldb_command('showztraces')
699 def ShowZTraces(cmd_args
=None):
700 """ Prints all traces with size > 0
702 ShowZTracesAbove([0])
704 #EndMacro: showztraces
706 #Macro: showztracesabove
708 @lldb_command('showztracesabove')
709 def ShowZTracesAbove(cmd_args
=None):
710 """ Prints all traces with size greater than X
711 Usage: showztracesabove <size>
714 print ShowZTracesAbove
.__doc
__
716 print '{0: <5s} {1: <6s}'.format('INDEX','SIZE')
719 max_ztrace
= unsigned(kern
.globals.zleak_trace_buckets
)
720 while current_index
< max_ztrace
:
721 ztrace_current
= kern
.globals.ztraces
[current_index
]
722 if ztrace_current
.zt_size
> unsigned(cmd_args
[0]):
723 print '{0: <5d} {1: <6d}'.format(current_index
, int(ztrace_current
.zt_size
))
726 print 'Total traces: {0: <d}'.format(ztrace_count
)
728 #EndMacro: showztracesabove
730 #Macro: showztracehistogram
732 @lldb_command('showztracehistogram')
733 def ShowZtraceHistogram(cmd_args
=None):
734 """ Prints the histogram of the ztrace table
736 print '{0: <5s} {1: <9s} {2: <10s}'.format('INDEX','HIT_COUNT','COLLISIONS')
739 max_ztrace
= unsigned(kern
.globals.zleak_trace_buckets
)
740 while current_index
< max_ztrace
:
741 ztrace_current
= kern
.globals.ztraces
[current_index
]
742 if ztrace_current
.zt_hit_count
!= 0:
743 print '{0: <5d} {1: <9d} {2: <10d}'.format(current_index
, ztrace_current
.zt_hit_count
, ztrace_current
.zt_collisions
)
746 print 'Total traces: {0: <d}'.format(ztrace_count
)
748 #EndMacro: showztracehistogram
750 #Macro: showzallochistogram
752 @lldb_command('showzallochistogram')
753 def ShowZallocHistogram(cmd_args
=None):
754 """ Prints the histogram for the zalloc table
756 print '{0: <5s} {1: <9s}'.format('INDEX','HIT_COUNT')
758 zallocation_count
= 0
759 max_ztrace
= unsigned(kern
.globals.zleak_alloc_buckets
)
760 while current_index
< max_ztrace
:
761 zallocation_current
= kern
.globals.zallocations
[current_index
]
762 if zallocation_current
.za_hit_count
!= 0:
763 print '{0: <5d} {1: <9d}'.format(current_index
, zallocation_current
.za_hit_count
)
764 zallocation_count
+= 1
766 print 'Total Allocations: {0: <d}'.format(zallocation_count
)
768 #EndMacro: showzallochistogram
772 @lldb_command('showzstats')
773 def ShowZstats(cmd_args
=None):
774 """ Prints the zone leak detection stats
776 print 'z_alloc_collisions: {0: <d}, z_trace_collisions: {1: <d}'.format(unsigned(kern
.globals.z_alloc_collisions
), unsigned(kern
.globals.z_trace_collisions
))
777 print 'z_alloc_overwrites: {0: <d}, z_trace_overwrites: {1: <d}'.format(unsigned(kern
.globals.z_alloc_overwrites
), unsigned(kern
.globals.z_trace_overwrites
))
778 print 'z_alloc_recorded: {0: <d}, z_trace_recorded: {1: <d}'.format(unsigned(kern
.globals.z_alloc_recorded
), unsigned(kern
.globals.z_trace_recorded
))
780 #EndMacro: showzstats
782 def GetBtlogBacktrace(depth
, zstack_record
):
783 """ Helper routine for getting a BT Log record backtrace stack.
785 depth:int - The depth of the zstack record
786 zstack_record:btlog_record_t * - A BTLog record
788 str - string with backtrace in it.
792 if not zstack_record
:
793 return "Zstack record none!"
795 depth_val
= unsigned(depth
)
796 while frame
< depth_val
:
797 frame_pc
= zstack_record
.bt
[frame
]
798 if not frame_pc
or int(frame_pc
) == 0:
800 symbol_arr
= kern
.SymbolicateFromAddress(frame_pc
)
802 symbol_str
= str(symbol_arr
[0].addr
)
805 out_str
+= "{0: <#0x} <{1: <s}>\n".format(frame_pc
, symbol_str
)
809 def ShowZStackRecord(zstack_record
, zstack_index
):
810 """ Helper routine for printing a single zstack record
812 zstack_record:btlog_record_t * - A BTLog record
813 zstack_index:int - Index for the record in the BTLog table
818 if zstack_record
.operation
== 1:
822 out_str
+= "{0: <#0x} : Index {1: <d} {2: <s}\n".format(zstack_record
.element
, zstack_index
, ('-' * 8))
824 print GetBtlogBacktrace(kern
.globals.zlog_btlog
.btrecord_btdepth
, zstack_record
)
828 @lldb_command('showioalloc')
829 def ShowIOAllocations(cmd_args
=None):
830 """ Show some accounting of memory allocated by IOKit allocators. See ioalloccount man page for details.
831 Routine to display a summary of memory accounting allocated by IOKit allocators.
833 print "Instance allocation = {0: <#0x} = {1: d}K".format(kern
.globals.debug_ivars_size
, (kern
.globals.debug_ivars_size
/ 1024))
834 print "Container allocation = {0: <#0x} = {1: d}K".format(kern
.globals.debug_container_malloc_size
, (kern
.globals.debug_container_malloc_size
/ 1024))
835 print "IOMalloc allocation = {0: <#0x} = {1: d}K".format(kern
.globals.debug_iomalloc_size
, (kern
.globals.debug_iomalloc_size
/ 1024))
836 print "Container allocation = {0: <#0x} = {1: d}K".format(kern
.globals.debug_iomallocpageable_size
, (kern
.globals.debug_iomallocpageable_size
/ 1024))
839 # EndMacro: showioalloc
845 @lldb_command('showtaskvme', "PS")
846 def ShowTaskVmeHelper(cmd_args
=None, cmd_options
={}):
847 """ Display a summary list of the specified vm_map's entries
848 Usage: showtaskvme <task address> (ex. showtaskvme 0x00ataskptr00 )
850 show_pager_info
= False
851 show_all_shadows
= False
852 if "-P" in cmd_options
:
853 show_pager_info
= True
854 if "-S" in cmd_options
:
855 show_all_shadows
= True
856 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
857 ShowTaskVMEntries(task
, show_pager_info
, show_all_shadows
)
859 @lldb_command('showallvme', "PS")
860 def ShowAllVME(cmd_args
=None, cmd_options
={}):
861 """ Routine to print a summary listing of all the vm map entries
862 Go Through each task in system and show the vm memory regions
863 Use -S flag to show VM object shadow chains
864 Use -P flag to show pager info (mapped file, compressed pages, ...)
866 show_pager_info
= False
867 show_all_shadows
= False
868 if "-P" in cmd_options
:
869 show_pager_info
= True
870 if "-S" in cmd_options
:
871 show_all_shadows
= True
872 for task
in kern
.tasks
:
873 ShowTaskVMEntries(task
, show_pager_info
, show_all_shadows
)
875 @lldb_command('showallvm')
876 def ShowAllVM(cmd_args
=None):
877 """ Routine to print a summary listing of all the vm maps
879 for task
in kern
.tasks
:
880 print GetTaskSummary
.header
+ ' ' + GetProcSummary
.header
881 print GetTaskSummary(task
) + ' ' + GetProcSummary(Cast(task
.bsd_info
, 'proc *'))
882 print GetVMMapSummary
.header
883 print GetVMMapSummary(task
.map)
885 @lldb_command("showtaskvm")
886 def ShowTaskVM(cmd_args
=None):
887 """ Display info about the specified task's vm_map
888 syntax: (lldb) showtaskvm <task_ptr>
891 print ShowTaskVM
.__doc
__
893 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
895 print "Unknown arguments."
897 print GetTaskSummary
.header
+ ' ' + GetProcSummary
.header
898 print GetTaskSummary(task
) + ' ' + GetProcSummary(Cast(task
.bsd_info
, 'proc *'))
899 print GetVMMapSummary
.header
900 print GetVMMapSummary(task
.map)
903 @lldb_command('showallvmstats')
904 def ShowAllVMStats(cmd_args
=None):
905 """ Print a summary of vm statistics in a table format
907 vmstats
= lambda:None
908 vmstats
.wired_count
= 0
909 vmstats
.resident_count
= 0
910 vmstats
.resident_max
= 0
914 vmstats
.compressed
= 0
915 vmstats
.compressed_peak
= 0
916 vmstats
.compressed_lifetime
= 0
919 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:}"
920 print hdr_format
.format('pid', 'command', '#ents', 'wired', 'vsize', 'rsize', 'NEW RSIZE', 'max rsize', 'internal', 'external', 'reusable', 'compressed', 'compressed', 'compressed', '')
921 print hdr_format
.format('', '', '', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(current)', '(peak)', '(lifetime)', '')
922 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}"
924 for task
in kern
.tasks
:
925 proc
= Cast(task
.bsd_info
, 'proc *')
926 vmmap
= Cast(task
.map, '_vm_map *')
928 vmstats
.wired_count
= vmmap
.pmap
.stats
.wired_count
;
929 vmstats
.resident_count
= unsigned(vmmap
.pmap
.stats
.resident_count
);
930 vmstats
.resident_max
= vmmap
.pmap
.stats
.resident_max
;
931 vmstats
.internal
= unsigned(vmmap
.pmap
.stats
.internal
);
932 vmstats
.external
= unsigned(vmmap
.pmap
.stats
.external
);
933 vmstats
.reusable
= unsigned(vmmap
.pmap
.stats
.reusable
);
934 vmstats
.compressed
= unsigned(vmmap
.pmap
.stats
.compressed
);
935 vmstats
.compressed_peak
= unsigned(vmmap
.pmap
.stats
.compressed_peak
);
936 vmstats
.compressed_lifetime
= unsigned(vmmap
.pmap
.stats
.compressed_lifetime
);
937 vmstats
.new_resident_count
= vmstats
.internal
+ vmstats
.external
939 if vmstats
.internal
< 0:
941 if vmstats
.external
< 0:
943 if vmstats
.reusable
< 0:
945 if vmstats
.compressed
< 0:
947 if vmstats
.compressed_peak
< 0:
949 if vmstats
.compressed_lifetime
< 0:
951 if vmstats
.new_resident_count
+vmstats
.reusable
!= vmstats
.resident_count
:
954 print entry_format
.format(p
=proc
, m
=vmmap
, vsize
=(unsigned(vmmap
.size
) >> 12), t
=task
, s
=vmstats
)
957 def ShowTaskVMEntries(task
, show_pager_info
, show_all_shadows
):
958 """ Routine to print out a summary listing of all the entries in a vm_map
960 task - core.value : a object of type 'task *'
964 print "vm_map entries for task " + hex(task
)
965 print GetTaskSummary
.header
966 print GetTaskSummary(task
)
968 print "Task {0: <#020x} has map = 0x0"
970 print GetVMMapSummary
.header
971 print GetVMMapSummary(task
.map)
972 vme_list_head
= task
.map.hdr
.links
973 vme_ptr_type
= GetType('vm_map_entry *')
974 print GetVMEntrySummary
.header
975 for vme
in IterateQueue(vme_list_head
, vme_ptr_type
, "links"):
976 print GetVMEntrySummary(vme
, show_pager_info
, show_all_shadows
)
979 @lldb_command("showmap")
980 def ShowMap(cmd_args
=None):
981 """ Routine to print out info about the specified vm_map
982 usage: showmap <vm_map>
984 if cmd_args
== None or len(cmd_args
) < 1:
985 print "Invalid argument.", ShowMap
.__doc
__
987 map_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vm_map_t')
988 print GetVMMapSummary
.header
989 print GetVMMapSummary(map_val
)
991 @lldb_command("showmapvme")
992 def ShowMapVME(cmd_args
=None):
993 """Routine to print out info about the specified vm_map and its vm entries
994 usage: showmapvme <vm_map>
996 if cmd_args
== None or len(cmd_args
) < 1:
997 print "Invalid argument.", ShowMap
.__doc
__
999 map_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vm_map_t')
1000 print GetVMMapSummary
.header
1001 print GetVMMapSummary(map_val
)
1002 vme_list_head
= map_val
.hdr
.links
1003 vme_ptr_type
= GetType('vm_map_entry *')
1004 print GetVMEntrySummary
.header
1005 for vme
in IterateQueue(vme_list_head
, vme_ptr_type
, "links"):
1006 print GetVMEntrySummary(vme
)
1009 @lldb_type_summary(['_vm_map *', 'vm_map_t'])
1010 @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"))
1011 def GetVMMapSummary(vmmap
):
1012 """ Display interesting bits from vm_map struct """
1014 format_string
= "{0: <#020x} {1: <#020x} {2: <#020x} {3: >5d} {4: >5d} {5: <#020x} {6: <#020x}"
1015 vm_size
= uint64_t(vmmap
.size
).value
1017 if vmmap
.pmap
!= 0: resident_pages
= int(vmmap
.pmap
.stats
.resident_count
)
1018 out_string
+= format_string
.format(vmmap
, vmmap
.pmap
, vm_size
, vmmap
.hdr
.nentries
, resident_pages
, vmmap
.hint
, vmmap
.first_free
)
1021 @lldb_type_summary(['vm_map_entry'])
1022 @header("{0: <20s} {1: <20s} {2: <5s} {3: >7s} {4: <20s} {5: <20s}".format("entry", "start", "prot", "#page", "object", "offset"))
1023 def GetVMEntrySummary(vme
):
1024 """ Display vm entry specific information. """
1026 format_string
= "{0: <#020x} {1: <#20x} {2: <1x}{3: <1x}{4: <3s} {5: >7d} {6: <#020x} {7: <#020x}"
1027 vme_protection
= int(vme
.protection
)
1028 vme_max_protection
= int(vme
.max_protection
)
1029 vme_extra_info_str
="SC-Ds"[int(vme
.inheritance
)]
1030 if int(vme
.is_sub_map
) != 0 :
1031 vme_extra_info_str
+="s"
1032 elif int(vme
.needs_copy
) != 0 :
1033 vme_extra_info_str
+="n"
1034 num_pages
= (unsigned(vme
.links
.end
) - unsigned(vme
.links
.start
)) >> 12
1035 out_string
+= format_string
.format(vme
, vme
.links
.start
, vme_protection
, vme_max_protection
, vme_extra_info_str
, num_pages
, vme
.object.vm_object
, vme
.offset
)
1038 # EndMacro: showtaskvme
1039 @lldb_command('showmapwired')
1040 def ShowMapWired(cmd_args
=None):
1041 """ Routine to print out a summary listing of all the entries with wired pages in a vm_map
1043 if cmd_args
== None or len(cmd_args
) < 1:
1044 print "Invalid argument", ShowMapWired
.__doc
__
1046 map_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vm_map_t')
1049 @lldb_type_summary(['kmod_info_t *'])
1050 @header("{0: <20s} {1: <20s} {2: <20s} {3: >3s} {4: >5s} {5: >20s} {6: <30s}".format('kmod_info', 'address', 'size', 'id', 'refs', 'version', 'name'))
1051 def GetKextSummary(kmod
):
1052 """ returns a string representation of kext information
1055 format_string
= "{0: <#020x} {1: <#020x} {2: <#020x} {3: >3d} {4: >5d} {5: >20s} {6: <30s}"
1056 out_string
+= format_string
.format(kmod
, kmod
.address
, kmod
.size
, kmod
.id, kmod
.reference_count
, kmod
.version
, kmod
.name
)
1059 @lldb_type_summary(['uuid_t'])
1061 def GetUUIDSummary(uuid
):
1062 """ returns a string representation like CA50DA4C-CA10-3246-B8DC-93542489AA26
1064 arr
= Cast(addressof(uuid
), 'uint8_t *')
1067 data
.append(int(arr
[i
]))
1068 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
)
1070 @lldb_command('showallkmods')
1071 def ShowAllKexts(cmd_args
=None):
1072 """Display a summary listing of all loaded kexts (alias: showallkmods)
1074 kmod_val
= kern
.globals.kmod
1075 print "{: <36s} ".format("UUID") + GetKextSummary
.header
1076 kextuuidinfo
= GetKextLoadInformation()
1077 for kval
in IterateLinkedList(kmod_val
, 'next'):
1078 uuid
= "........-....-....-....-............"
1079 kaddr
= unsigned(kval
.address
)
1080 for l
in kextuuidinfo
:
1081 if kaddr
== int(l
[1],16):
1084 print uuid
+ " " + GetKextSummary(kval
)
1086 def GetKextLoadInformation(addr
=0):
1087 """ Extract the kext uuid and load address information from the kernel data structure.
1089 addr - int - optional integer that is the address to search for.
1091 [] - array with each entry of format ( 'UUID', 'Hex Load Address')
1093 # because of <rdar://problem/12683084>, we can't find summaries directly
1094 #addr = hex(addressof(kern.globals.gLoadedKextSummaries.summaries))
1095 baseaddr
= unsigned(kern
.globals.gLoadedKextSummaries
) + 0x10
1096 summaries_begin
= kern
.GetValueFromAddress(baseaddr
, 'OSKextLoadedKextSummary *')
1097 total_summaries
= int(kern
.globals.gLoadedKextSummaries
.numSummaries
)
1098 kext_version
= int(kern
.globals.gLoadedKextSummaries
.version
)
1099 entry_size
= 64 + 16 + 8 + 8 + 8 + 4 + 4
1100 if kext_version
>= 2 :
1101 entry_size
= int(kern
.globals.gLoadedKextSummaries
.entry_size
)
1103 for i
in range(total_summaries
):
1104 tmpaddress
= unsigned(summaries_begin
) + (i
* entry_size
)
1105 current_kext
= kern
.GetValueFromAddress(tmpaddress
, 'OSKextLoadedKextSummary *')
1107 if addr
== unsigned(current_kext
.address
):
1108 retval
.append((GetUUIDSummary(current_kext
.uuid
) , hex(current_kext
.address
), str(current_kext
.name
) ))
1110 retval
.append((GetUUIDSummary(current_kext
.uuid
) , hex(current_kext
.address
), str(current_kext
.name
) ))
1114 lldb_alias('showallkexts', 'showallkmods')
1116 def GetOSKextVersion(version_num
):
1117 """ returns a string of format 1.2.3x from the version_num
1118 params: version_num - int
1121 if version_num
== -1 :
1123 (MAJ_MULT
, MIN_MULT
, REV_MULT
,STAGE_MULT
) = (100000000, 1000000, 10000, 1000)
1124 version
= version_num
1126 vers_major
= version
/ MAJ_MULT
1127 version
= version
- (vers_major
* MAJ_MULT
)
1129 vers_minor
= version
/ MIN_MULT
1130 version
= version
- (vers_minor
* MIN_MULT
)
1132 vers_revision
= version
/ REV_MULT
1133 version
= version
- (vers_revision
* REV_MULT
)
1135 vers_stage
= version
/ STAGE_MULT
1136 version
= version
- (vers_stage
* STAGE_MULT
)
1138 vers_stage_level
= version
1140 out_str
= "%d.%d" % (vers_major
, vers_minor
)
1141 if vers_revision
> 0: out_str
+= ".%d" % vers_revision
1142 if vers_stage
== 1 : out_str
+= "d%d" % vers_stage_level
1143 if vers_stage
== 3 : out_str
+= "a%d" % vers_stage_level
1144 if vers_stage
== 5 : out_str
+= "b%d" % vers_stage_level
1145 if vers_stage
== 6 : out_str
+= "fc%d" % vers_stage_level
1149 @lldb_command('showallknownkmods')
1150 def ShowAllKnownKexts(cmd_args
=None):
1151 """ Display a summary listing of all kexts known in the system.
1152 This is particularly useful to find if some kext was unloaded before this crash'ed state.
1154 kext_count
= int(kern
.globals.sKextsByID
.count
)
1156 kext_dictionary
= kern
.globals.sKextsByID
.dictionary
1157 print "%d kexts in sKextsByID:" % kext_count
1158 print "{0: <20s} {1: <20s} {2: >5s} {3: >20s} {4: <30s}".format('OSKEXT *', 'load_addr', 'id', 'version', 'name')
1159 format_string
= "{0: <#020x} {1: <20s} {2: >5s} {3: >20s} {4: <30s}"
1161 while index
< kext_count
:
1162 kext_dict
= GetObjectAtIndexFromArray(kext_dictionary
, index
)
1163 kext_name
= str(kext_dict
.key
.string
)
1164 osk
= Cast(kext_dict
.value
, 'OSKext *')
1165 if int(osk
.flags
.loaded
) :
1166 load_addr
= "{0: <#020x}".format(osk
.kmod_info
)
1167 id = "{0: >5d}".format(osk
.loadTag
)
1169 load_addr
= "------"
1171 version_num
= unsigned(osk
.version
)
1172 version
= GetOSKextVersion(version_num
)
1173 print format_string
.format(osk
, load_addr
, id, version
, kext_name
)
1178 @lldb_command('showkmodaddr')
1179 def ShowKmodAddr(cmd_args
=[]):
1180 """ Given an address, print the offset and name for the kmod containing it
1181 Syntax: (lldb) showkmodaddr <addr>
1183 if len(cmd_args
) < 1:
1184 raise ArgumentError("Insufficient arguments")
1186 addr
= ArgumentStringToInt(cmd_args
[0])
1187 kmod_val
= kern
.globals.kmod
1188 for kval
in IterateLinkedList(kmod_val
, 'next'):
1189 if addr
>= unsigned(kval
.address
) and addr
<= (unsigned(kval
.address
) + unsigned(kval
.size
)):
1190 print GetKextSummary
.header
1191 print GetKextSummary(kval
) + " offset = {0: #0x}".format((addr
- unsigned(kval
.address
)))
1195 @lldb_command('addkext','AF:N:')
1196 def AddKextSyms(cmd_args
=[], cmd_options
={}):
1197 """ Add kext symbols into lldb.
1198 This command finds symbols for a uuid and load the required executable
1200 addkext <uuid> : Load one kext based on uuid. eg. (lldb)addkext 4DD2344C0-4A81-3EAB-BDCF-FEAFED9EB73E
1201 addkext -F <abs/path/to/executable> <load_address> : Load kext executable at specified load address
1202 addkext -N <name> : Load one kext that matches the name provided. eg. (lldb) addkext -N corecrypto
1203 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
1204 addkext all : Will load all the kext symbols - SLOW
1208 if "-F" in cmd_options
:
1209 exec_path
= cmd_options
["-F"]
1210 exec_full_path
= ResolveFSPath(exec_path
)
1211 if not os
.path
.exists(exec_full_path
):
1212 raise ArgumentError("Unable to resolve {:s}".format(exec_path
))
1214 if not os
.path
.isfile(exec_full_path
):
1215 raise ArgumentError("Path is {:s} not a filepath. \nPlease check that path points to executable.\
1216 \nFor ex. path/to/Symbols/IOUSBFamily.kext/Contents/PlugIns/AppleUSBHub.kext/Contents/MacOS/AppleUSBHub.\
1217 \nNote: LLDB does not support adding kext based on directory paths like gdb used to.".format(exec_path
))
1218 if not os
.access(exec_full_path
, os
.X_OK
):
1219 raise ArgumentError("Path is {:s} not an executable file".format(exec_path
))
1223 slide_value
= cmd_args
[0]
1224 debuglog("loading slide value from user input %s" % cmd_args
[0])
1226 filespec
= lldb
.SBFileSpec(exec_full_path
, False)
1227 print "target modules add %s" % exec_full_path
1228 print lldb_run_command("target modules add %s" % exec_full_path
)
1229 loaded_module
= LazyTarget
.GetTarget().FindModule(filespec
)
1230 if loaded_module
.IsValid():
1231 uuid_str
= loaded_module
.GetUUIDString()
1232 debuglog("added module %s with uuid %s" % (exec_full_path
, uuid_str
))
1233 if slide_value
is None:
1234 all_kexts_info
= GetKextLoadInformation()
1235 for k
in all_kexts_info
:
1237 if k
[0].lower() == uuid_str
.lower():
1239 debuglog("found the slide %s for uuid %s" % (k
[1], k
[0]))
1241 if slide_value
is None:
1242 raise ArgumentError("Unable to find load address for module described at %s " % exec_full_path
)
1243 load_cmd
= "target modules load --file %s --slide %s" % (exec_full_path
, str(slide_value
))
1245 print lldb_run_command(load_cmd
)
1246 kern
.symbolicator
= None
1249 all_kexts_info
= GetKextLoadInformation()
1251 if "-N" in cmd_options
:
1252 kext_name
= cmd_options
["-N"]
1253 kext_name_matches
= GetLongestMatchOption(kext_name
, [str(x
[2]) for x
in all_kexts_info
], True)
1254 if len(kext_name_matches
) != 1 and "-A" not in cmd_options
:
1255 print "Ambiguous match for name: {:s}".format(kext_name
)
1256 if len(kext_name_matches
) > 0:
1257 print "Options are:\n\t" + "\n\t".join(kext_name_matches
)
1259 debuglog("matched the kext to name %s and uuid %s" % (kext_name_matches
[0], kext_name
))
1260 for cur_knm
in kext_name_matches
:
1261 for x
in all_kexts_info
:
1263 cur_uuid
= x
[0].lower()
1264 print "Fetching dSYM for {:s}".format(cur_uuid
)
1265 info
= dsymForUUID(cur_uuid
)
1266 if info
and 'DBGSymbolRichExecutable' in info
:
1267 print "Adding dSYM ({0:s}) for {1:s}".format(cur_uuid
, info
['DBGSymbolRichExecutable'])
1268 addDSYM(cur_uuid
, info
)
1269 loadDSYM(cur_uuid
, int(x
[1],16))
1271 print "Failed to get symbol info for {:s}".format(cur_uuid
)
1273 kern
.symbolicator
= None
1276 if len(cmd_args
) < 1:
1277 raise ArgumentError("No arguments specified.")
1279 uuid
= cmd_args
[0].lower()
1281 load_all_kexts
= False
1283 load_all_kexts
= True
1285 if not load_all_kexts
and len(uuid_regex
.findall(uuid
)) == 0:
1286 raise ArgumentError("Unknown argument {:s}".format(uuid
))
1288 for k_info
in all_kexts_info
:
1289 cur_uuid
= k_info
[0].lower()
1290 if load_all_kexts
or (uuid
== cur_uuid
):
1291 print "Fetching dSYM for %s" % cur_uuid
1292 info
= dsymForUUID(cur_uuid
)
1293 if info
and 'DBGSymbolRichExecutable' in info
:
1294 print "Adding dSYM (%s) for %s" % (cur_uuid
, info
['DBGSymbolRichExecutable'])
1295 addDSYM(cur_uuid
, info
)
1296 loadDSYM(cur_uuid
, int(k_info
[1],16))
1298 print "Failed to get symbol info for %s" % cur_uuid
1300 kern
.symbolicator
= None
1305 lldb_alias('showkmod', 'showkmodaddr')
1306 lldb_alias('showkext', 'showkmodaddr')
1307 lldb_alias('showkextaddr', 'showkmodaddr')
1309 @lldb_type_summary(['mount *'])
1310 @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'))
1311 def GetMountSummary(mount
):
1312 """ Display a summary of mount on the system
1314 out_string
= ("{mnt: <#020x} {mnt.mnt_data: <#020x} {mnt.mnt_devvp: <#020x} {mnt.mnt_flag: <#012x} " +
1315 "{mnt.mnt_kern_flag: <#012x} {mnt.mnt_lflag: <#012x} {vfs.f_fstypename: >6s} " +
1316 "{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'))
1319 @lldb_command('showallmounts')
1320 def ShowAllMounts(cmd_args
=None):
1321 """ Print all mount points
1323 mntlist
= kern
.globals.mountlist
1324 print GetMountSummary
.header
1325 for mnt
in IterateTAILQ_HEAD(mntlist
, 'mnt_list'):
1326 print GetMountSummary(mnt
)
1329 lldb_alias('ShowAllVols', 'showallmounts')
1331 @lldb_command('systemlog')
1332 def ShowSystemLog(cmd_args
=None):
1333 """ Display the kernel's printf ring buffer """
1334 msgbufp
= kern
.globals.msgbufp
1335 msg_size
= int(msgbufp
.msg_size
)
1336 msg_bufx
= int(msgbufp
.msg_bufx
)
1337 msg_bufr
= int(msgbufp
.msg_bufr
)
1338 msg_bufc
= msgbufp
.msg_bufc
1339 msg_bufc_data
= msg_bufc
.GetSBValue().GetPointeeData(0, msg_size
)
1341 # the buffer is circular; start at the write pointer to end,
1342 # then from beginning to write pointer
1344 err
= lldb
.SBError()
1345 for i
in range(msg_bufx
, msg_size
) + range(0, msg_bufx
) :
1347 cbyte
= msg_bufc_data
.GetUnsignedInt8(err
, i
)
1348 if not err
.Success() :
1349 raise ValueError("Failed to read character at offset " + str(i
) + ": " + err
.GetCString())
1364 @static_var('output','')
1365 def _GetVnodePathName(vnode
, vnodename
):
1366 """ Internal function to get vnode path string from vnode structure.
1370 returns Nothing. The output will be stored in the static variable.
1374 if int(vnode
.v_flag
) & 0x1 and int(hex(vnode
.v_mount
), 16) !=0:
1375 if int(vnode
.v_mount
.mnt_vnodecovered
):
1376 _GetVnodePathName(vnode
.v_mount
.mnt_vnodecovered
, str(vnode
.v_mount
.mnt_vnodecovered
.v_name
) )
1378 _GetVnodePathName(vnode
.v_parent
, str(vnode
.v_parent
.v_name
))
1379 _GetVnodePathName
.output
+= "/%s" % vnodename
1381 def GetVnodePath(vnode
):
1382 """ Get string representation of the vnode
1383 params: vnodeval - value representing vnode * in the kernel
1384 return: str - of format /path/to/something
1388 if (int(vnode
.v_flag
) & 0x000001) and int(hex(vnode
.v_mount
), 16) != 0 and (int(vnode
.v_mount
.mnt_flag
) & 0x00004000) :
1391 _GetVnodePathName
.output
= ''
1392 if abs(vnode
.v_name
) != 0:
1393 _GetVnodePathName(vnode
, str(vnode
.v_name
))
1394 out_str
+= _GetVnodePathName
.output
1396 out_str
+= 'v_name = NULL'
1397 _GetVnodePathName
.output
= ''
1401 @lldb_command('showvnodepath')
1402 def ShowVnodePath(cmd_args
=None):
1403 """ Prints the path for a vnode
1404 usage: showvnodepath <vnode>
1406 if cmd_args
!= None and len(cmd_args
) > 0 :
1407 vnode_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vnode *')
1409 print GetVnodePath(vnode_val
)
1412 # Macro: showvnodedev
1413 def GetVnodeDevInfo(vnode
):
1414 """ Internal function to get information from the device type vnodes
1415 params: vnode - value representing struct vnode *
1416 return: str - formatted output information for block and char vnode types passed as param
1418 vnodedev_output
= ""
1419 vblk_type
= GetEnumValue('vtype::VBLK')
1420 vchr_type
= GetEnumValue('vtype::VCHR')
1421 if (vnode
.v_type
== vblk_type
) or (vnode
.v_type
== vchr_type
):
1422 devnode
= Cast(vnode
.v_data
, 'devnode_t *')
1423 devnode_dev
= devnode
.dn_typeinfo
.dev
1424 devnode_major
= (devnode_dev
>> 24) & 0xff
1425 devnode_minor
= devnode_dev
& 0x00ffffff
1427 # boilerplate device information for a vnode
1428 vnodedev_output
+= "Device Info:\n\t vnode:\t\t{:#x}".format(vnode
)
1429 vnodedev_output
+= "\n\t type:\t\t"
1430 if (vnode
.v_type
== vblk_type
):
1431 vnodedev_output
+= "VBLK"
1432 if (vnode
.v_type
== vchr_type
):
1433 vnodedev_output
+= "VCHR"
1434 vnodedev_output
+= "\n\t name:\t\t{:<s}".format(vnode
.v_name
)
1435 vnodedev_output
+= "\n\t major, minor:\t{:d},{:d}".format(devnode_major
, devnode_minor
)
1436 vnodedev_output
+= "\n\t mode\t\t0{:o}".format(unsigned(devnode
.dn_mode
))
1437 vnodedev_output
+= "\n\t owner (u,g):\t{:d} {:d}".format(devnode
.dn_uid
, devnode
.dn_gid
)
1439 # decode device specific data
1440 vnodedev_output
+= "\nDevice Specific Information:\t"
1441 if (vnode
.v_type
== vblk_type
):
1442 vnodedev_output
+= "Sorry, I do not know how to decode block devices yet!"
1443 vnodedev_output
+= "\nMaybe you can write me!"
1445 if (vnode
.v_type
== vchr_type
):
1446 # Device information; this is scanty
1448 if (devnode_major
> 42) or (devnode_major
< 0):
1449 vnodedev_output
+= "Invalid major #\n"
1450 # static assignments in conf
1451 elif (devnode_major
== 0):
1452 vnodedev_output
+= "Console mux device\n"
1453 elif (devnode_major
== 2):
1454 vnodedev_output
+= "Current tty alias\n"
1455 elif (devnode_major
== 3):
1456 vnodedev_output
+= "NULL device\n"
1457 elif (devnode_major
== 4):
1458 vnodedev_output
+= "Old pty slave\n"
1459 elif (devnode_major
== 5):
1460 vnodedev_output
+= "Old pty master\n"
1461 elif (devnode_major
== 6):
1462 vnodedev_output
+= "Kernel log\n"
1463 elif (devnode_major
== 12):
1464 vnodedev_output
+= "Memory devices\n"
1465 # Statically linked dynamic assignments
1466 elif unsigned(kern
.globals.cdevsw
[devnode_major
].d_open
) == unsigned(kern
.GetLoadAddressForSymbol('ptmx_open')):
1467 vnodedev_output
+= "Cloning pty master not done\n"
1468 #GetVnodeDevCpty(devnode_major, devnode_minor)
1469 elif unsigned(kern
.globals.cdevsw
[devnode_major
].d_open
) == unsigned(kern
.GetLoadAddressForSymbol('ptsd_open')):
1470 vnodedev_output
+= "Cloning pty slave not done\n"
1471 #GetVnodeDevCpty(devnode_major, devnode_minor)
1473 vnodedev_output
+= "RESERVED SLOT\n"
1475 vnodedev_output
+= "{:#x} is not a device".format(vnode
)
1476 return vnodedev_output
1478 @lldb_command('showvnodedev')
1479 def ShowVnodeDev(cmd_args
=None):
1480 """ Routine to display details of all vnodes of block and character device types
1481 Usage: showvnodedev <address of vnode>
1484 print "No arguments passed"
1485 print ShowVnodeDev
.__doc
__
1487 vnode_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vnode *')
1489 print "unknown arguments:", str(cmd_args
)
1491 print GetVnodeDevInfo(vnode_val
)
1493 # EndMacro: showvnodedev
1495 # Macro: showvnodelocks
1496 def GetVnodeLock(lockf
):
1497 """ Internal function to get information from the given advisory lock
1498 params: lockf - value representing v_lockf member in struct vnode *
1499 return: str - formatted output information for the advisory lock
1501 vnode_lock_output
= ''
1502 lockf_flags
= lockf
.lf_flags
1503 lockf_type
= lockf
.lf_type
1504 if lockf_flags
& 0x20:
1505 vnode_lock_output
+= ("{: <8s}").format('flock')
1506 if lockf_flags
& 0x40:
1507 vnode_lock_output
+= ("{: <8s}").format('posix')
1508 if lockf_flags
& 0x80:
1509 vnode_lock_output
+= ("{: <8s}").format('prov')
1510 if lockf_flags
& 0x10:
1511 vnode_lock_output
+= ("{: <4s}").format('W')
1513 vnode_lock_output
+= ("{: <4s}").format('.')
1515 # POSIX file vs advisory range locks
1516 if lockf_flags
& 0x40:
1517 lockf_proc
= Cast(lockf
.lf_id
, 'proc *')
1518 vnode_lock_output
+= ("PID {: <18d}").format(lockf_proc
.p_pid
)
1520 vnode_lock_output
+= ("ID {: <#019x}").format(int(lockf
.lf_id
))
1524 vnode_lock_output
+= ("{: <12s}").format('shared')
1527 vnode_lock_output
+= ("{: <12s}").format('exclusive')
1530 vnode_lock_output
+= ("{: <12s}").format('unlock')
1532 vnode_lock_output
+= ("{: <12s}").format('unknown')
1534 # start and stop values
1535 vnode_lock_output
+= ("{: #018x} ..").format(lockf
.lf_start
)
1536 vnode_lock_output
+= ("{: #018x}\n").format(lockf
.lf_end
)
1537 return vnode_lock_output
1539 @header("{0: <3s} {1: <7s} {2: <3s} {3: <21s} {4: <11s} {5: ^19s} {6: ^17s}".format('*', 'type', 'W', 'held by', 'lock type', 'start', 'end'))
1540 def GetVnodeLocksSummary(vnode
):
1541 """ Internal function to get summary of advisory locks for the given vnode
1542 params: vnode - value representing the vnode object
1543 return: str - formatted output information for the summary of advisory locks
1547 lockf_list
= vnode
.v_lockf
1548 for lockf_itr
in IterateLinkedList(lockf_list
, 'lf_next'):
1549 out_str
+= ("{: <4s}").format('H')
1550 out_str
+= GetVnodeLock(lockf_itr
)
1551 lockf_blocker
= lockf_itr
.lf_blkhd
.tqh_first
1552 while lockf_blocker
:
1553 out_str
+= ("{: <4s}").format('>')
1554 out_str
+= GetVnodeLock(lockf_blocker
)
1555 lockf_blocker
= lockf_blocker
.lf_block
.tqe_next
1558 @lldb_command('showvnodelocks')
1559 def ShowVnodeLocks(cmd_args
=None):
1560 """ Routine to display list of advisory record locks for the given vnode address
1561 Usage: showvnodelocks <address of vnode>
1564 print "No arguments passed"
1565 print ShowVnodeLocks
.__doc
__
1567 vnode_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vnode *')
1569 print "unknown arguments:", str(cmd_args
)
1571 print GetVnodeLocksSummary
.header
1572 print GetVnodeLocksSummary(vnode_val
)
1574 # EndMacro: showvnodelocks
1576 # Macro: showproclocks
1578 @lldb_command('showproclocks')
1579 def ShowProcLocks(cmd_args
=None):
1580 """ Routine to display list of advisory record locks for the given process
1581 Usage: showproclocks <address of proc>
1584 print "No arguments passed"
1585 print ShowProcLocks
.__doc
__
1587 proc
= kern
.GetValueFromAddress(cmd_args
[0], 'proc *')
1589 print "unknown arguments:", str(cmd_args
)
1592 proc_filedesc
= proc
.p_fd
1593 fd_lastfile
= proc_filedesc
.fd_lastfile
1594 fd_ofiles
= proc_filedesc
.fd_ofiles
1597 while count
<= fd_lastfile
:
1598 if fd_ofiles
[count
]:
1599 fglob
= fd_ofiles
[count
].f_fglob
1600 fo_type
= fglob
.fg_ops
.fo_type
1602 fg_data
= fglob
.fg_data
1603 fg_vnode
= Cast(fg_data
, 'vnode *')
1604 name
= fg_vnode
.v_name
1605 lockf_itr
= fg_vnode
.v_lockf
1608 print GetVnodeLocksSummary
.header
1610 out_str
+= ("\n( fd {:d}, name ").format(count
)
1612 out_str
+= "(null) )\n"
1614 out_str
+= "{:s} )\n".format(name
)
1616 print GetVnodeLocksSummary(fg_vnode
)
1618 print "\n{0: d} total locks for {1: #018x}".format(seen
, proc
)
1620 # EndMacro: showproclocks
1622 @lldb_type_summary(['vnode_t', 'vnode *'])
1623 @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'))
1624 def GetVnodeSummary(vnode
):
1625 """ Get a summary of important information out of vnode
1628 format_string
= "{0: <#020x} {1: >8d} {2: >8d} {3: <#020x} {4: <6s} {5: <#020x} {6: <6s} {7: <6s} {8: <35s}"
1629 usecount
= int(vnode
.v_usecount
)
1630 iocount
= int(vnode
.v_iocount
)
1631 v_data_ptr
= int(hex(vnode
.v_data
), 16)
1632 vtype
= int(vnode
.v_type
)
1633 vtype_str
= "%d" % vtype
1634 vnode_types
= ['VNON', 'VREG', 'VDIR', 'VBLK', 'VCHR', 'VLNK', 'VSOCK', 'VFIFO', 'VBAD', 'VSTR', 'VCPLX'] # see vnode.h for enum type definition
1635 if vtype
>= 0 and vtype
< len(vnode_types
):
1636 vtype_str
= vnode_types
[vtype
]
1637 parent_ptr
= int(hex(vnode
.v_parent
), 16)
1638 name_ptr
= int(hex(vnode
.v_name
), 16)
1641 name
= str(vnode
.v_name
)
1642 elif int(vnode
.v_tag
) == 16 :
1643 cnode
= Cast(vnode
.v_data
, 'cnode *')
1644 name
= "hfs: %s" % str( Cast(cnode
.c_desc
.cd_nameptr
, 'char *'))
1646 csblob_version
= '-'
1647 if (vtype
== 1) and (vnode
.v_un
.vu_ubcinfo
!= 0):
1648 csblob_version
= '{: <6d}'.format(vnode
.v_un
.vu_ubcinfo
.cs_add_gen
)
1649 # Check to see if vnode is mapped/unmapped
1650 if (vnode
.v_un
.vu_ubcinfo
.ui_flags
& 0x8) != 0:
1654 out_str
+= format_string
.format(vnode
, usecount
, iocount
, v_data_ptr
, vtype_str
, parent_ptr
, mapped
, csblob_version
, name
)
1657 @lldb_command('showallvnodes')
1658 def ShowAllVnodes(cmd_args
=None):
1659 """ Display info about all vnodes
1661 mntlist
= kern
.globals.mountlist
1662 print GetVnodeSummary
.header
1663 for mntval
in IterateTAILQ_HEAD(mntlist
, 'mnt_list'):
1664 for vnodeval
in IterateTAILQ_HEAD(mntval
.mnt_vnodelist
, 'v_mntvnodes'):
1665 print GetVnodeSummary(vnodeval
)
1668 @lldb_command('showvnode')
1669 def ShowVnode(cmd_args
=None):
1670 """ Display info about one vnode
1671 usage: showvnode <vnode>
1673 if cmd_args
== None or len(cmd_args
) < 1:
1674 print "Please provide valid vnode argument. Type help showvnode for help."
1676 vnodeval
= kern
.GetValueFromAddress(cmd_args
[0],'vnode *')
1677 print GetVnodeSummary
.header
1678 print GetVnodeSummary(vnodeval
)
1680 @lldb_command('showvolvnodes')
1681 def ShowVolVnodes(cmd_args
=None):
1682 """ Display info about all vnodes of a given mount_t
1684 if cmd_args
== None or len(cmd_args
) < 1:
1685 print "Please provide a valide mount_t argument. Try 'help showvolvnodes' for help"
1687 mntval
= kern
.GetValueFromAddress(cmd_args
[0], 'mount_t')
1688 print GetVnodeSummary
.header
1689 for vnodeval
in IterateTAILQ_HEAD(mntval
.mnt_vnodelist
, 'v_mntvnodes'):
1690 print GetVnodeSummary(vnodeval
)
1693 @lldb_command('showvolbusyvnodes')
1694 def ShowVolBusyVnodes(cmd_args
=None):
1695 """ Display info about busy (iocount!=0) vnodes of a given mount_t
1697 if cmd_args
== None or len(cmd_args
) < 1:
1698 print "Please provide a valide mount_t argument. Try 'help showvolbusyvnodes' for help"
1700 mntval
= kern
.GetValueFromAddress(cmd_args
[0], 'mount_t')
1701 print GetVnodeSummary
.header
1702 for vnodeval
in IterateTAILQ_HEAD(mntval
.mnt_vnodelist
, 'v_mntvnodes'):
1703 if int(vnodeval
.v_iocount
) != 0:
1704 print GetVnodeSummary(vnodeval
)
1706 @lldb_command('showallbusyvnodes')
1707 def ShowAllBusyVnodes(cmd_args
=None):
1708 """ Display info about all busy (iocount!=0) vnodes
1710 mntlistval
= kern
.globals.mountlist
1711 for mntval
in IterateTAILQ_HEAD(mntlistval
, 'mnt_list'):
1712 ShowVolBusyVnodes([hex(mntval
)])
1714 @lldb_command('print_vnode')
1715 def PrintVnode(cmd_args
=None):
1716 """ Prints out the fields of a vnode struct
1717 Usage: print_vnode <vnode>
1720 print "Please provide valid vnode argument. Type help print_vnode for help."
1724 @lldb_command('showworkqvnodes')
1725 def ShowWorkqVnodes(cmd_args
=None):
1726 """ Print the vnode worker list
1727 Usage: showworkqvnodes <struct mount *>
1730 print "Please provide valid mount argument. Type help showworkqvnodes for help."
1733 mp
= kern
.GetValueFromAddress(cmd_args
[0], 'mount *')
1734 vp
= Cast(mp
.mnt_workerqueue
.tqh_first
, 'vnode *')
1735 print GetVnodeSummary
.header
1737 print GetVnodeSummary(vp
)
1738 vp
= vp
.v_mntvnodes
.tqe_next
1740 @lldb_command('shownewvnodes')
1741 def ShowNewVnodes(cmd_args
=None):
1742 """ Print the new vnode list
1743 Usage: shownewvnodes <struct mount *>
1746 print "Please provide valid mount argument. Type help shownewvnodes for help."
1748 mp
= kern
.GetValueFromAddress(cmd_args
[0], 'mount *')
1749 vp
= Cast(mp
.mnt_newvnodes
.tqh_first
, 'vnode *')
1750 print GetVnodeSummary
.header
1752 print GetVnodeSummary(vp
)
1753 vp
= vp
.v_mntvnodes
.tqe_next
1756 @lldb_command('showprocvnodes')
1757 def ShowProcVnodes(cmd_args
=None):
1758 """ Routine to print out all the open fds which are vnodes in a process
1759 Usage: showprocvnodes <proc *>
1762 print "Please provide valid proc argument. Type help showprocvnodes for help."
1764 procptr
= kern
.GetValueFromAddress(cmd_args
[0], 'proc *')
1765 fdptr
= Cast(procptr
.p_fd
, 'filedesc *')
1766 if int(fdptr
.fd_cdir
) != 0:
1767 print '{0: <25s}\n{1: <s}\n{2: <s}'.format('Current Working Directory:', GetVnodeSummary
.header
, GetVnodeSummary(fdptr
.fd_cdir
))
1768 if int(fdptr
.fd_rdir
) != 0:
1769 print '{0: <25s}\n{1: <s}\n{2: <s}'.format('Current Root Directory:', GetVnodeSummary
.header
, GetVnodeSummary(fdptr
.fd_rdir
))
1771 print '\n' + '{0: <5s} {1: <7s}'.format('fd', 'flags') + GetVnodeSummary
.header
1772 # Hack to get around <rdar://problem/12879494> llb fails to cast addresses to double pointers
1773 fpptr
= Cast(fdptr
.fd_ofiles
, 'fileproc *')
1774 while count
< fdptr
.fd_nfiles
:
1775 fpp
= dereference(fpptr
)
1776 fproc
= Cast(fpp
, 'fileproc *')
1778 fglob
= dereference(fproc
).f_fglob
1780 if (int(fglob
) != 0) and (int(fglob
.fg_ops
.fo_type
) == 1):
1781 if (fdptr
.fd_ofileflags
[count
] & 1): flags
+= 'E'
1782 if (fdptr
.fd_ofileflags
[count
] & 2): flags
+= 'F'
1783 if (fdptr
.fd_ofileflags
[count
] & 4): flags
+= 'R'
1784 if (fdptr
.fd_ofileflags
[count
] & 8): flags
+= 'C'
1785 print '{0: <5d} {1: <7s}'.format(count
, flags
) + GetVnodeSummary(Cast(fglob
.fg_data
, 'vnode *'))
1787 fpptr
= kern
.GetValueFromAddress(int(fpptr
) + kern
.ptrsize
,'fileproc *')
1789 @lldb_command('showallprocvnodes')
1790 def ShowAllProcVnodes(cmd_args
=None):
1791 """ Routine to print out all the open fds which are vnodes
1794 procptr
= Cast(kern
.globals.allproc
.lh_first
, 'proc *')
1795 while procptr
and int(procptr
) != 0:
1796 print '{:<s}'.format("=" * 106)
1797 print GetProcInfo(procptr
)
1798 ShowProcVnodes([int(procptr
)])
1799 procptr
= procptr
.p_list
.le_next
1801 @xnudebug_test('test_vnode')
1802 def TestShowAllVnodes(kernel_target
, config
, lldb_obj
, isConnected
):
1803 """ Test the functionality of vnode related commands
1809 print "Target is not connected. Cannot test memstats"
1811 res
= lldb
.SBCommandReturnObject()
1812 lldb_obj
.debugger
.GetCommandInterpreter().HandleCommand("showallvnodes", res
)
1813 result
= res
.GetOutput()
1814 if len(result
.split("\n")) > 2 and result
.find('VREG') != -1 and len(result
.splitlines()[2].split()) > 5:
1820 @lldb_type_summary(['_lck_grp_ *'])
1821 def GetMutexEntry(mtxg
):
1822 """ Summarize a mutex group entry with important information.
1824 mtxg: value - obj representing a mutex group in kernel
1826 out_string - summary of the mutex group
1830 if kern
.ptrsize
== 8:
1831 format_string
= '{0:#018x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1833 format_string
= '{0:#010x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1835 if mtxg
.lck_grp_mtxcnt
:
1836 out_string
+= format_string
.format(mtxg
, mtxg
.lck_grp_mtxcnt
,mtxg
.lck_grp_stat
.lck_grp_mtx_stat
.lck_grp_mtx_util_cnt
,
1837 mtxg
.lck_grp_stat
.lck_grp_mtx_stat
.lck_grp_mtx_miss_cnt
,
1838 mtxg
.lck_grp_stat
.lck_grp_mtx_stat
.lck_grp_mtx_wait_cnt
, mtxg
.lck_grp_name
)
1841 @lldb_command('showallmtx')
1842 def ShowAllMtx(cmd_args
=None):
1843 """ Routine to print a summary listing of all mutexes
1846 if kern
.ptrsize
== 8:
1847 hdr_format
= '{:<18s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
1849 hdr_format
= '{:<10s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
1851 print hdr_format
.format('LCK GROUP', 'CNT', 'UTIL', 'MISS', 'WAIT', 'NAME')
1853 mtxgrp_queue_head
= kern
.globals.lck_grp_queue
1854 mtxgrp_ptr_type
= GetType('_lck_grp_ *')
1856 for mtxgrp_ptr
in IterateQueue(mtxgrp_queue_head
, mtxgrp_ptr_type
, "lck_grp_link"):
1857 print GetMutexEntry(mtxgrp_ptr
)
1859 # EndMacro: showallmtx
1861 # Macro: showallrwlck
1862 @lldb_type_summary(['_lck_grp_ *'])
1863 def GetRWLEntry(rwlg
):
1864 """ Summarize a reader writer lock group with important information.
1866 rwlg: value - obj representing a reader writer lock group in kernel
1868 out_string - summary of the reader writer lock group
1872 if kern
.ptrsize
== 8:
1873 format_string
= '{0:#018x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1875 format_string
= '{0:#010x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1877 if rwlg
.lck_grp_rwcnt
:
1878 out_string
+= format_string
.format(rwlg
, rwlg
.lck_grp_rwcnt
,rwlg
.lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_util_cnt
,
1879 rwlg
.lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
,
1880 rwlg
.lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_wait_cnt
, rwlg
.lck_grp_name
)
1884 @lldb_type_summary(['lck_mtx_t *'])
1885 @header("===== Mutex Lock Summary =====")
1886 def GetMutexLockSummary(mtx
):
1887 """ Summarize mutex lock with important information.
1889 mtx: value - obj representing a mutex lock in kernel
1891 out_str - summary of the mutex lock
1894 return "Invalid lock value: 0x0"
1896 if kern
.arch
== "x86_64":
1897 out_str
= "Lock Type\t\t: MUTEX\n"
1898 mtxd
= mtx
.lck_mtx_sw
.lck_mtxd
1899 out_str
+= "Owner Thread\t\t: {:#x}\n".format(mtxd
.lck_mtxd_owner
)
1900 cmd_str
= "p/d ((lck_mtx_t*){:#x})->lck_mtx_sw.lck_mtxd.".format(mtx
)
1901 cmd_out
= lldb_run_command(cmd_str
+ "lck_mtxd_waiters")
1902 out_str
+= "Number of Waiters\t: {:s}\n".format(cmd_out
.split()[-1])
1903 cmd_out
= lldb_run_command(cmd_str
+ "lck_mtxd_ilocked")
1904 out_str
+= "ILocked\t\t\t: {:s}\n".format(cmd_out
.split()[-1])
1905 cmd_out
= lldb_run_command(cmd_str
+ "lck_mtxd_mlocked")
1906 out_str
+= "MLocked\t\t\t: {:s}\n".format(cmd_out
.split()[-1])
1907 cmd_out
= lldb_run_command(cmd_str
+ "lck_mtxd_promoted")
1908 out_str
+= "Promoted\t\t: {:s}\n".format(cmd_out
.split()[-1])
1909 cmd_out
= lldb_run_command(cmd_str
+ "lck_mtxd_spin")
1910 out_str
+= "Spin\t\t\t: {:s}\n".format(cmd_out
.split()[-1])
1913 out_str
= "Lock Type\t\t: MUTEX\n"
1914 out_str
+= "Owner Thread\t\t: {:#x}\n".format(mtx
.lck_mtx_hdr
.lck_mtxd_data
& ~
0x3)
1915 out_str
+= "Number of Waiters\t: {:d}\n".format(mtx
.lck_mtx_sw
.lck_mtxd
.lck_mtxd_waiters
)
1916 out_str
+= "Flags\t\t\t: "
1917 if mtx
.lck_mtx_hdr
.lck_mtxd_data
& 0x1:
1918 out_str
+= "[Interlock Locked] "
1919 if mtx
.lck_mtx_hdr
.lck_mtxd_data
& 0x2:
1920 out_str
+= "[Wait Flag]"
1921 if (mtx
.lck_mtx_hdr
.lck_mtxd_data
& 0x3) == 0:
1925 @lldb_type_summary(['lck_spin_t *'])
1926 @header("===== SpinLock Summary =====")
1927 def GetSpinLockSummary(spinlock
):
1928 """ Summarize spinlock with important information.
1930 spinlock: value - obj representing a spinlock in kernel
1932 out_str - summary of the spinlock
1935 return "Invalid lock value: 0x0"
1937 out_str
= "Lock Type\t\t: SPINLOCK\n"
1938 if kern
.arch
== "x86_64":
1939 out_str
+= "Interlock\t\t: {:#x}\n".format(spinlock
.interlock
)
1942 out_str
+= "Owner Thread\t\t: {:#x}\n".format(spinlock
.lck_spin_data
& ~
0x3)
1943 out_str
+= "Flags\t\t\t: "
1944 if spinlock
.lck_spin_data
& 0x1:
1945 out_str
+= "[Interlock Locked] "
1946 if spinlock
.lck_spin_data
& 0x2:
1947 out_str
+= "[Wait Flag]"
1948 if (spinlock
.lck_spin_data
& 0x3) == 0:
1952 @lldb_command('showlock', 'MS')
1953 def ShowLock(cmd_args
=None, cmd_options
={}):
1954 """ Show info about a lock - its state and owner thread details
1955 Usage: showlock <address of a lock>
1956 -M : to consider <addr> as lck_mtx_t
1957 -S : to consider <addr> as lck_spin_t
1960 raise ArgumentError("Please specify the address of the lock whose info you want to view.")
1964 lock
= kern
.GetValueFromAddress(cmd_args
[0], 'uintptr_t*')
1966 if kern
.arch
== "x86_64" and lock
:
1967 if "-M" in cmd_options
:
1968 lock_mtx
= Cast(lock
, 'lck_mtx_t *')
1969 summary_str
= GetMutexLockSummary(lock_mtx
)
1970 elif "-S" in cmd_options
:
1971 lock_spin
= Cast(lock
, 'lck_spin_t *')
1972 summary_str
= GetSpinLockSummary(lock_spin
)
1974 summary_str
= "Please specify supported lock option(-M/-S)"
1980 lock_mtx
= Cast(lock
, 'lck_mtx_t*')
1981 if lock_mtx
.lck_mtx_type
== 0x22:
1982 summary_str
= GetMutexLockSummary(lock_mtx
)
1984 lock_spin
= Cast(lock
, 'lck_spin_t*')
1985 if lock_spin
.lck_spin_type
== 0x11:
1986 summary_str
= GetSpinLockSummary(lock_spin
)
1988 if summary_str
== "":
1989 summary_str
= "Lock Type\t\t: INVALID LOCK"
1994 @lldb_command('showallrwlck')
1995 def ShowAllRWLck(cmd_args
=None):
1996 """ Routine to print a summary listing of all read/writer locks
1998 if kern
.ptrsize
== 8:
1999 hdr_format
= '{:<18s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
2001 hdr_format
= '{:<10s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
2003 print hdr_format
.format('LCK GROUP', 'CNT', 'UTIL', 'MISS', 'WAIT', 'NAME')
2005 rwlgrp_queue_head
= kern
.globals.lck_grp_queue
2006 rwlgrp_ptr_type
= GetType('_lck_grp_ *')
2007 for rwlgrp_ptr
in IterateQueue(rwlgrp_queue_head
, rwlgrp_ptr_type
, "lck_grp_link"):
2008 print GetRWLEntry(rwlgrp_ptr
)
2010 # EndMacro: showallrwlck
2012 #Macro: showbootermemorymap
2013 @lldb_command('showbootermemorymap')
2014 def ShowBooterMemoryMap(cmd_args
=None):
2015 """ Prints out the phys memory map from kernelBootArgs
2016 Supported only on x86_64
2018 if kern
.arch
== 'x86_64':
2019 voffset
= unsigned(0xFFFFFF8000000000)
2021 print "showbootermemorymap not supported on this architecture"
2044 boot_args
= kern
.globals.kernelBootArgs
2045 msize
= boot_args
.MemoryMapDescriptorSize
2046 mcount
= (boot_args
.MemoryMapSize
) / unsigned(msize
)
2048 out_string
+= "{0: <12s} {1: <19s} {2: <19s} {3: <19s} {4: <10s}\n".format("Type", "Physical Start", "Number of Pages", "Virtual Start", "Attributes")
2052 mptr
= kern
.GetValueFromAddress(unsigned(boot_args
.MemoryMap
) + voffset
+ unsigned(i
*msize
), 'EfiMemoryRange *')
2053 mtype
= unsigned(mptr
.Type
)
2054 if mtype
in memtype_dict
:
2055 out_string
+= "{0: <12s}".format(memtype_dict
[mtype
])
2057 out_string
+= "{0: <12s}".format("UNKNOWN")
2059 if mptr
.VirtualStart
== 0:
2060 out_string
+= "{0: #019x} {1: #019x} {2: <19s} {3: #019x}\n".format(mptr
.PhysicalStart
, mptr
.NumberOfPages
, ' '*19, mptr
.Attribute
)
2062 out_string
+= "{0: #019x} {1: #019x} {2: #019x} {3: #019x}\n".format(mptr
.PhysicalStart
, mptr
.NumberOfPages
, mptr
.VirtualStart
, mptr
.Attribute
)
2066 #EndMacro: showbootermemorymap
2068 @lldb_command('show_all_purgeable_objects')
2069 def ShowAllPurgeableVmObjects(cmd_args
=None):
2070 """ Routine to print a summary listing of all the purgeable vm objects
2072 print "\n-------------------- VOLATILE OBJECTS --------------------\n"
2073 ShowAllPurgeableVolatileVmObjects()
2074 print "\n-------------------- NON-VOLATILE OBJECTS --------------------\n"
2075 ShowAllPurgeableNonVolatileVmObjects()
2077 @lldb_command('show_all_purgeable_nonvolatile_objects')
2078 def ShowAllPurgeableNonVolatileVmObjects(cmd_args
=None):
2079 """ Routine to print a summary listing of all the vm objects in
2080 the purgeable_nonvolatile_queue
2083 nonvolatile_total
= lambda:None
2084 nonvolatile_total
.objects
= 0
2085 nonvolatile_total
.vsize
= 0
2086 nonvolatile_total
.rsize
= 0
2087 nonvolatile_total
.wsize
= 0
2088 nonvolatile_total
.csize
= 0
2089 nonvolatile_total
.disowned_objects
= 0
2090 nonvolatile_total
.disowned_vsize
= 0
2091 nonvolatile_total
.disowned_rsize
= 0
2092 nonvolatile_total
.disowned_wsize
= 0
2093 nonvolatile_total
.disowned_csize
= 0
2095 queue_len
= kern
.globals.purgeable_nonvolatile_count
2096 queue_head
= kern
.globals.purgeable_nonvolatile_queue
2098 print 'purgeable_nonvolatile_queue:{:#018x} purgeable_volatile_count:{:d}\n'.format(kern
.GetLoadAddressForSymbol('purgeable_nonvolatile_queue'),queue_len
)
2099 print 'N:non-volatile V:volatile E:empty D:deny\n'
2101 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")
2103 for object in IterateQueue(queue_head
, 'struct vm_object *', 'objq'):
2105 ShowPurgeableNonVolatileVmObject(object, idx
, queue_len
, nonvolatile_total
)
2106 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
)
2107 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
)
2110 def ShowPurgeableNonVolatileVmObject(object, idx
, queue_len
, nonvolatile_total
):
2111 """ Routine to print out a summary a VM object in purgeable_nonvolatile_queue
2113 object - core.value : a object of type 'struct vm_object *'
2117 if object.purgable
== 0:
2119 elif object.purgable
== 1:
2121 elif object.purgable
== 2:
2123 elif object.purgable
== 3:
2127 if object.pager
== 0:
2128 compressed_count
= 0
2130 compressor_pager
= Cast(object.pager
, 'compressor_pager *')
2131 compressed_count
= compressor_pager
.cpgr_num_slots_occupied
2133 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
/kern
.globals.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
))
2135 nonvolatile_total
.objects
+= 1
2136 nonvolatile_total
.vsize
+= object.vo_un1
.vou_size
/kern
.globals.page_size
2137 nonvolatile_total
.rsize
+= object.resident_page_count
2138 nonvolatile_total
.wsize
+= object.wired_page_count
2139 nonvolatile_total
.csize
+= compressed_count
2140 if object.vo_un2
.vou_purgeable_owner
== 0:
2141 nonvolatile_total
.disowned_objects
+= 1
2142 nonvolatile_total
.disowned_vsize
+= object.vo_un1
.vou_size
/kern
.globals.page_size
2143 nonvolatile_total
.disowned_rsize
+= object.resident_page_count
2144 nonvolatile_total
.disowned_wsize
+= object.wired_page_count
2145 nonvolatile_total
.disowned_csize
+= compressed_count
2148 @lldb_command('show_all_purgeable_volatile_objects')
2149 def ShowAllPurgeableVolatileVmObjects(cmd_args
=None):
2150 """ Routine to print a summary listing of all the vm objects in
2151 the purgeable queues
2153 volatile_total
= lambda:None
2154 volatile_total
.objects
= 0
2155 volatile_total
.vsize
= 0
2156 volatile_total
.rsize
= 0
2157 volatile_total
.wsize
= 0
2158 volatile_total
.csize
= 0
2159 volatile_total
.disowned_objects
= 0
2160 volatile_total
.disowned_vsize
= 0
2161 volatile_total
.disowned_rsize
= 0
2162 volatile_total
.disowned_wsize
= 0
2163 volatile_total
.disowned_csize
= 0
2165 purgeable_queues
= kern
.globals.purgeable_queues
2166 print "---------- OBSOLETE\n"
2167 ShowPurgeableQueue(purgeable_queues
[0], volatile_total
)
2168 print "\n\n---------- FIFO\n"
2169 ShowPurgeableQueue(purgeable_queues
[1], volatile_total
)
2170 print "\n\n---------- LIFO\n"
2171 ShowPurgeableQueue(purgeable_queues
[2], volatile_total
)
2173 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
)
2174 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
)
2175 purgeable_count
= kern
.globals.vm_page_purgeable_count
2176 purgeable_wired_count
= kern
.globals.vm_page_purgeable_wired_count
2177 if purgeable_count
!= volatile_total
.rsize
or purgeable_wired_count
!= volatile_total
.wsize
:
2178 mismatch
= "<--------- MISMATCH\n"
2181 print "vm_page_purgeable_count: resident:{:<10d} wired:{:<10d} {:s}\n".format(purgeable_count
, purgeable_wired_count
, mismatch
)
2184 def ShowPurgeableQueue(qhead
, volatile_total
):
2185 print "----- GROUP 0\n"
2186 ShowPurgeableGroup(qhead
.objq
[0], volatile_total
)
2187 print "----- GROUP 1\n"
2188 ShowPurgeableGroup(qhead
.objq
[1], volatile_total
)
2189 print "----- GROUP 2\n"
2190 ShowPurgeableGroup(qhead
.objq
[2], volatile_total
)
2191 print "----- GROUP 3\n"
2192 ShowPurgeableGroup(qhead
.objq
[3], volatile_total
)
2193 print "----- GROUP 4\n"
2194 ShowPurgeableGroup(qhead
.objq
[4], volatile_total
)
2195 print "----- GROUP 5\n"
2196 ShowPurgeableGroup(qhead
.objq
[5], volatile_total
)
2197 print "----- GROUP 6\n"
2198 ShowPurgeableGroup(qhead
.objq
[6], volatile_total
)
2199 print "----- GROUP 7\n"
2200 ShowPurgeableGroup(qhead
.objq
[7], volatile_total
)
2202 def ShowPurgeableGroup(qhead
, volatile_total
):
2204 for object in IterateQueue(qhead
, 'struct vm_object *', 'objq'):
2206 # 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","")
2207 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")
2209 ShowPurgeableVolatileVmObject(object, idx
, volatile_total
)
2211 def ShowPurgeableVolatileVmObject(object, idx
, volatile_total
):
2212 """ Routine to print out a summary a VM object in a purgeable queue
2214 object - core.value : a object of type 'struct vm_object *'
2218 # if int(object.vo_un2.vou_purgeable_owner) != int(object.vo_purgeable_volatilizer):
2222 if object.purgable
== 0:
2224 elif object.purgable
== 1:
2226 elif object.purgable
== 2:
2228 elif object.purgable
== 3:
2232 if object.pager
== 0:
2233 compressed_count
= 0
2235 compressor_pager
= Cast(object.pager
, 'compressor_pager *')
2236 compressed_count
= compressor_pager
.cpgr_num_slots_occupied
2237 # 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/kern.globals.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)
2238 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
/kern
.globals.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
))
2239 volatile_total
.objects
+= 1
2240 volatile_total
.vsize
+= object.vo_un1
.vou_size
/kern
.globals.page_size
2241 volatile_total
.rsize
+= object.resident_page_count
2242 volatile_total
.wsize
+= object.wired_page_count
2243 volatile_total
.csize
+= compressed_count
2244 if object.vo_un2
.vou_purgeable_owner
== 0:
2245 volatile_total
.disowned_objects
+= 1
2246 volatile_total
.disowned_vsize
+= object.vo_un1
.vou_size
/kern
.globals.page_size
2247 volatile_total
.disowned_rsize
+= object.resident_page_count
2248 volatile_total
.disowned_wsize
+= object.wired_page_count
2249 volatile_total
.disowned_csize
+= compressed_count
2252 def GetCompressedPagesForObject(obj
):
2255 pager
= Cast(obj
.pager
, 'compressor_pager_t')
2256 return pager
.cpgr_num_slots_occupied
2257 # if pager.cpgr_num_slots > 128:
2258 # slots_arr = pager.cpgr_slots.cpgr_islots
2259 # num_indirect_slot_ptr = (pager.cpgr_num_slots + 127) / 128
2261 # compressor_slot = 0
2262 # compressed_pages = 0
2263 # while index < num_indirect_slot_ptr:
2264 # compressor_slot = 0
2265 # if slots_arr[index]:
2266 # while compressor_slot < 128:
2267 # if slots_arr[index][compressor_slot]:
2268 # compressed_pages += 1
2269 # compressor_slot += 1
2272 # slots_arr = pager.cpgr_slots.cpgr_dslots
2273 # compressor_slot = 0
2274 # compressed_pages = 0
2275 # while compressor_slot < pager.cpgr_num_slots:
2276 # if slots_arr[compressor_slot]:
2277 # compressed_pages += 1
2278 # compressor_slot += 1
2279 # return compressed_pages
2281 @lldb_command('showallvme', "-PS")
2282 def ShowAllVME(cmd_args
=None, cmd_options
={}):
2283 """ Routine to print a summary listing of all the vm map entries
2284 Go Through each task in system and show the vm info
2286 show_pager_info
= False
2287 show_all_shadows
= False
2288 if "-P" in cmd_options
:
2289 show_pager_info
= True
2290 if "-S" in cmd_options
:
2291 show_all_shadows
= True
2292 for task
in kern
.tasks
:
2293 ShowTaskVMEntries(task
, show_pager_info
, show_all_shadows
)
2295 def ShowTaskVMEntries(task
, show_pager_info
, show_all_shadows
):
2296 """ Routine to print out a summary listing of all the entries in a vm_map
2298 task - core.value : a object of type 'task *'
2302 print "vm_map entries for task " + hex(task
)
2303 print GetTaskSummary
.header
2304 print GetTaskSummary(task
)
2306 print "Task {0: <#020x} has map = 0x0"
2308 showmapvme(task
.map, show_pager_info
, show_all_shadows
)
2310 @lldb_command("showmapvme", "PS")
2311 def ShowMapVME(cmd_args
=None, cmd_options
={}):
2312 """Routine to print out info about the specified vm_map and its vm entries
2313 usage: showmapvme <vm_map>
2315 if cmd_args
== None or len(cmd_args
) < 1:
2316 print "Invalid argument.", ShowMap
.__doc
__
2318 show_pager_info
= False
2319 show_all_shadows
= False
2320 if "-P" in cmd_options
:
2321 show_pager_info
= True
2322 if "-S" in cmd_options
:
2323 show_all_shadows
= True
2324 map = kern
.GetValueFromAddress(cmd_args
[0], 'vm_map_t')
2325 showmapvme(map, show_pager_info
, show_all_shadows
)
2327 def showmapvme(map, show_pager_info
, show_all_shadows
):
2328 vnode_pager_ops
= kern
.globals.vnode_pager_ops
2329 vnode_pager_ops_addr
= unsigned(addressof(vnode_pager_ops
))
2332 rsize
= int(map.pmap
.stats
.resident_count
)
2333 print "{:<18s} {:<18s} {:<18s} {:>10s} {:>10s} {:>18s}:{:<18s}".format("vm_map","pmap","size","#ents","rsize","start","end")
2334 print "{:#018x} {:#018x} {:#018x} {:>10d} {:>10d} {:#018x}:{:#018x}".format(map,map.pmap
,(map.size
/4096),map.hdr
.nentries
,rsize
,map.hdr
.links
.start
,map.hdr
.links
.end
)
2335 vme_list_head
= map.hdr
.links
2336 vme_ptr_type
= GetType('vm_map_entry *')
2337 print "{:<18s} {:>18s}:{:<18s} {:>10s} {:>3s} {:<10s} {:<18s} {:<18s}".format("entry","start","end","#pgs","tag","prot&flags","object","offset")
2338 last_end
= map.hdr
.links
.start
2339 for vme
in IterateQueue(vme_list_head
, vme_ptr_type
, "links"):
2340 if vme
.links
.start
!= last_end
:
2341 print "{:18s} {:#018x}:{:#018x} {:>10d}".format("------------------",last_end
,vme
.links
.start
,(vme
.links
.start
-last_end
)/4096)
2342 last_end
= vme
.links
.end
2346 print "{:#018x} {:#018x}:{:#018x} {:>10d} {:>3d} {:1d}{:1d}{:<8s} {:#018x} {:<#18x}".format(vme
,vme
.links
.start
,vme
.links
.end
,(vme
.links
.end
-vme
.links
.start
)/4096,vme
.alias
,vme
.protection
,vme
.max_protection
,vme_flags
,vme
.object.vm_object
,vme
.offset
)
2347 if show_pager_info
and vme
.is_sub_map
== 0 and vme
.object.vm_object
!= 0:
2348 object = vme
.object.vm_object
2352 offset
= unsigned(vme
.offset
)
2353 size
= vme
.links
.end
- vme
.links
.start
2356 if show_all_shadows
== False and depth
!= 1 and object.shadow
!= 0:
2357 offset
+= unsigned(object.vo_un2
.vou_shadow_offset
)
2358 object = object.shadow
2360 if object.copy_strategy
== 0:
2362 elif object.copy_strategy
== 2:
2364 elif object.copy_strategy
== 4:
2367 copy_strategy
=str(object.copy_strategy
)
2369 internal
= "internal"
2371 internal
= "external"
2373 if show_pager_info
and object.pager
!= 0:
2375 pager_string
= "-> compressed:{:d}".format(GetCompressedPagesForObject(object))
2377 vnode_pager
= Cast(object.pager
,'vnode_pager *')
2378 if unsigned(vnode_pager
.pager_ops
) == vnode_pager_ops_addr
:
2379 pager_string
= "-> " + GetVnodePath(vnode_pager
.vnode_handle
)
2380 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
)/4096,object.resident_page_count
,object.wired_page_count
,pager_string
)
2381 # 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/4096,object.wired_page_count,object.resident_page_count,object.reusable_page_count)
2382 offset
+= unsigned(object.vo_un2
.vou_shadow_offset
)
2383 object = object.shadow
2386 def FindVMEntriesForVnode(task
, vn
):
2387 """ returns an array of vme that have the vnode set to defined vnode
2388 each entry in array is of format (vme, start_addr, end_address, protection)
2393 pager_ops_addr
= unsigned(addressof(kern
.globals.vnode_pager_ops
))
2394 debuglog("pager_ops_addr %s" % hex(pager_ops_addr
))
2396 if unsigned(pmap
) == 0:
2398 vme_list_head
= vmmap
.hdr
.links
2399 vme_ptr_type
= gettype('vm_map_entry *')
2400 for vme
in IterateQueue(vme_list_head
, vme_ptr_type
, 'links'):
2402 if unsigned(vme
.is_sub_map
) == 0 and unsigned(vme
.object.vm_object
) != 0:
2403 obj
= vme
.object.vm_object
2412 vn_pager
= Cast(obj
.pager
, 'vnode_pager *')
2413 if unsigned(vn_pager
.pager_ops
) == pager_ops_addr
and unsigned(vn_pager
.vnode_handle
) == unsigned(vn
):
2414 retval
.append((vme
, unsigned(vme
.links
.start
), unsigned(vme
.links
.end
), unsigned(vme
.protection
)))
2418 @lldb_command('showtaskloadinfo')
2419 def ShowTaskLoadInfo(cmd_args
=None, cmd_options
={}):
2420 """ Print the load address and uuid for the process
2421 Usage: (lldb)showtaskloadinfo <task_t>
2424 raise ArgumentError("Insufficient arguments")
2425 t
= kern
.GetValueFromAddress(cmd_args
[0], 'struct task *')
2426 print_format
= "0x{0:x} - 0x{1:x} {2: <50s} (??? - ???) <{3: <36s}> {4: <50s}"
2427 p
= Cast(t
.bsd_info
, 'struct proc *')
2429 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
)
2430 filepath
= GetVnodePath(p
.p_textvp
)
2431 libname
= filepath
.split('/')[-1]
2432 #print "uuid: %s file: %s" % (uuid_out_string, filepath)
2433 mappings
= FindVMEntriesForVnode(t
, p
.p_textvp
)
2440 #print "Load address: %s" % hex(m[1])
2441 print print_format
.format(load_addr
, end_addr
, libname
, uuid_out_string
, filepath
)