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.
12 @lldb_command('memstats')
13 def Memstats(cmd_args
=None):
14 """ 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.
17 print "memorystatus_level: {: >10d}".format(kern
.globals.memorystatus_level
)
21 print "memorystatus_available_pages: {: >10d}".format(kern
.globals.memorystatus_available_pages
)
24 print "vm_page_throttled_count: {: >10d}".format(kern
.globals.vm_page_throttled_count
)
25 print "vm_page_active_count: {: >10d}".format(kern
.globals.vm_page_active_count
)
26 print "vm_page_inactive_count: {: >10d}".format(kern
.globals.vm_page_inactive_count
)
27 print "vm_page_wire_count: {: >10d}".format(kern
.globals.vm_page_wire_count
)
28 print "vm_page_free_count: {: >10d}".format(kern
.globals.vm_page_free_count
)
29 print "vm_page_purgeable_count: {: >10d}".format(kern
.globals.vm_page_purgeable_count
)
30 print "vm_page_inactive_target: {: >10d}".format(kern
.globals.vm_page_inactive_target
)
31 print "vm_page_free_target: {: >10d}".format(kern
.globals.vm_page_free_target
)
32 print "inuse_ptepages_count: {: >10d}".format(kern
.globals.inuse_ptepages_count
)
33 print "vm_page_free_reserved: {: >10d}".format(kern
.globals.vm_page_free_reserved
)
35 @xnudebug_test('test_memstats')
36 def TestMemstats(kernel_target
, config
, lldb_obj
, isConnected
):
37 """ Test the functionality of memstats command
43 print "Target is not connected. Cannot test memstats"
45 res
= lldb
.SBCommandReturnObject()
46 lldb_obj
.debugger
.GetCommandInterpreter().HandleCommand("memstats", res
)
47 result
= res
.GetOutput()
48 if result
.split(":")[1].strip().find('None') == -1 :
55 # Macro: showmemorystatus
56 def CalculateLedgerPeak(phys_footprint_entry
):
57 """ Internal function to calculate ledger peak value for the given phys footprint entry
58 params: phys_footprint_entry - value representing struct ledger_entry *
59 return: value - representing the ledger peak for the given phys footprint entry
61 now
= kern
.globals.sched_tick
/ 20
62 ledger_peak
= phys_footprint_entry
.le_credit
- phys_footprint_entry
.le_debit
63 if (now
- phys_footprint_entry
._le
.le_peaks
[0].le_time
<= 1) and (phys_footprint_entry
._le
.le_peaks
[0].le_max
> ledger_peak
):
64 ledger_peak
= phys_footprint_entry
._le
.le_peaks
[0].le_max
65 if (now
- phys_footprint_entry
._le
.le_peaks
[1].le_time
<= 1) and (phys_footprint_entry
._le
.le_peaks
[1].le_max
> ledger_peak
):
66 ledger_peak
= phys_footprint_entry
._le
.le_peaks
[1].le_max
69 @header("{: >8s} {: >22s} {: >22s} {: >11s} {: >11s} {: >12s} {: >10s} {: >13s} {: ^10s} {: >8s} {: <20s}\n".format(
70 'pid', 'effective priority', 'requested priority', 'state', 'user_data', 'physical', 'iokit', 'footprint',
71 'spike', 'limit', 'command'))
72 def GetMemoryStatusNode(proc_val
):
73 """ Internal function to get memorystatus information from the given proc
74 params: proc - value representing struct proc *
75 return: str - formatted output information for proc object
78 task_val
= Cast(proc_val
.task
, 'task *')
79 task_ledgerp
= task_val
.ledger
81 task_physmem_footprint_ledger_entry
= task_ledgerp
.l_entries
[kern
.globals.task_ledgers
.phys_mem
]
82 task_iokit_footprint_ledger_entry
= task_ledgerp
.l_entries
[kern
.globals.task_ledgers
.iokit_mem
]
83 task_phys_footprint_ledger_entry
= task_ledgerp
.l_entries
[kern
.globals.task_ledgers
.phys_footprint
]
84 page_size
= kern
.globals.page_size
86 phys_mem_footprint
= (task_physmem_footprint_ledger_entry
.le_credit
- task_physmem_footprint_ledger_entry
.le_debit
) / page_size
87 iokit_footprint
= (task_iokit_footprint_ledger_entry
.le_credit
- task_iokit_footprint_ledger_entry
.le_debit
) / page_size
88 phys_footprint
= (task_phys_footprint_ledger_entry
.le_credit
- task_phys_footprint_ledger_entry
.le_debit
) / page_size
89 phys_footprint_limit
= task_phys_footprint_ledger_entry
.le_limit
/ page_size
90 ledger_peak
= CalculateLedgerPeak(task_phys_footprint_ledger_entry
)
91 phys_footprint_spike
= ledger_peak
/ page_size
93 format_string
= '{0: >8d} {1: >22d} {2: >22d} {3: #011x} {4: #011x} {5: >12d} {6: >10d} {7: >13d}'
94 out_str
+= format_string
.format(proc_val
.p_pid
, proc_val
.p_memstat_effectivepriority
,
95 proc_val
.p_memstat_requestedpriority
, proc_val
.p_memstat_state
, proc_val
.p_memstat_userdata
,
96 phys_mem_footprint
, iokit_footprint
, phys_footprint
)
97 if phys_footprint
!= phys_footprint_spike
:
98 out_str
+= "{: ^12d}".format(phys_footprint_spike
)
100 out_str
+= "{: ^12s}".format('-')
101 out_str
+= "{: 8d} {: <20s}\n".format(phys_footprint_limit
, proc_val
.p_comm
)
104 @lldb_command('showmemorystatus')
105 def ShowMemoryStatus(cmd_args
=None):
106 """ Routine to display each entry in jetsam list with a summary of pressure statistics
107 Usage: showmemorystatus
111 print GetMemoryStatusNode
.header
112 print "{: >91s} {: >10s} {: >13s} {: ^10s} {: >8s}\n".format("(pages)", "(pages)", "(pages)",
113 "(pages)", "(pages)")
114 while bucket_index
< bucket_count
:
115 current_bucket
= kern
.globals.memstat_bucket
[bucket_index
]
116 current_list
= current_bucket
.list
117 current_proc
= Cast(current_list
.tqh_first
, 'proc *')
118 while unsigned(current_proc
) != 0:
119 print GetMemoryStatusNode(current_proc
)
120 current_proc
= current_proc
.p_memstat_list
.tqe_next
125 # EndMacro: showmemorystatus
129 @lldb_type_summary(['zone','zone_t'])
130 @header("{:^18s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s}({:>6s} {:>6s} {:>6s}) {:^14s} {:<20s}".format(
131 'ZONE', 'TOT_SZ', 'PAGE_COUNT', 'ALLOC_ELTS', 'FREE_ELTS', 'FREE_SZ', 'ELT_SZ', 'ALLOC', 'ELTS', 'PGS', 'SLK', 'FLAGS', 'NAME'))
132 def GetZoneSummary(zone
):
133 """ Summarize a zone with important information. See help zprint for description of each field
135 zone: value - obj representing a zone in kernel
137 str - summary of the zone
140 format_string
= '{:#018x} {:10d} {:10d} {:10d} {:10d} {:10d} {:10d} {:10d} {:6d} {:6d} {:6d} {markings} {name:s} '
143 free_elements
= (zone
.cur_size
/ zone
.elem_size
) - zone
.count
144 free_size
= free_elements
* zone
.elem_size
146 alloc_count
= zone
.alloc_size
/ zone
.elem_size
147 alloc_pages
= zone
.alloc_size
/ pagesize
148 alloc_slack
= zone
.alloc_size
% zone
.elem_size
150 ["collectable", "C"],
153 ["caller_acct", "@"],
154 ["exhaustible", "H"],
155 ["allows_foreign", "F"],
156 ["async_prio_refill", "R"],
159 ["doing_alloc", "A"],
163 if kern
.arch
== 'x86_64':
164 marks
.append(["gzalloc_exempt", "M"])
165 marks
.append(["alignment_required", "N"])
169 if zone
.__getattr
__(mark
[0]) :
173 out_string
+= format_string
.format(zone
, zone
.cur_size
, zone
.page_count
,
174 zone
.count
, free_elements
, free_size
,
175 zone
.elem_size
, zone
.alloc_size
, alloc_count
,
176 alloc_pages
, alloc_slack
, name
= zone
.zone_name
, markings
=markings
)
178 if zone
.exhaustible
:
179 out_string
+= "(max: {:d})".format(zone
.max_size
)
183 @lldb_command('zprint')
184 def Zprint(cmd_args
=None):
185 """ Routine to print a summary listing of all the kernel zones
186 All columns are printed in decimal
190 $ - not encrypted during hibernation
191 @ - allocs and frees are accounted to caller process for KPRVT
193 F - allows foreign memory (memory not allocated from zone_map)
194 M - gzalloc will avoid monitoring this zone
195 R - will be refilled when below low water mark
196 O - does not allow refill callout to fill zone on noblock allocation
197 N - zone requires alignment (avoids padding this zone for debugging)
198 A - currently trying to allocate more backing memory from kernel_memory_allocate
199 W - another thread is waiting for more memory
200 L - zone is being monitored by zleaks
201 G - currently running GC
204 print GetZoneSummary
.header
205 for zval
in kern
.zones
:
206 print GetZoneSummary(zval
)
208 @xnudebug_test('test_zprint')
209 def TestZprint(kernel_target
, config
, lldb_obj
, isConnected
):
210 """ Test the functionality of zprint command
216 print "Target is not connected. Cannot test memstats"
218 res
= lldb
.SBCommandReturnObject()
219 lldb_obj
.debugger
.GetCommandInterpreter().HandleCommand("zprint", res
)
220 result
= res
.GetOutput()
221 if len(result
.split("\n")) > 2:
229 # Macro: showzfreelist
231 def ShowZfreeListHeader(zone
):
232 """ Helper routine to print a header for zone freelist.
233 (Since the freelist does not have a custom type, this is not defined as a Type Summary).
235 zone:zone_t - Zone object to print header info
240 out_str
+= "{0: <9s} {1: <12s} {2: <18s} {3: <18s} {4: <6s}\n".format('ELEM_SIZE', 'COUNT', 'NCOOKIE', 'PCOOKIE', 'FACTOR')
241 out_str
+= "{0: <9d} {1: <12d} 0x{2:0>16x} 0x{3:0>16x} {4: <2d}/{5: <2d}\n\n".format(
242 zone
.elem_size
, zone
.count
, kern
.globals.zp_nopoison_cookie
, kern
.globals.zp_poisoned_cookie
, zone
.zp_count
, kern
.globals.zp_factor
)
243 out_str
+= "{0: <7s} {1: <18s} {2: <18s} {3: <18s} {4: <18s} {5: <18s} {6: <14s}\n".format(
244 'NUM', 'ELEM', 'NEXT', 'BACKUP', '^ NCOOKIE', '^ PCOOKIE', 'POISON (PREV)')
247 def ShowZfreeListChain(zone
, zfirst
, zlimit
):
248 """ Helper routine to print a zone free list chain
250 zone: zone_t - Zone object
251 zfirst: void * - A pointer to the first element of the free list chain
252 zlimit: int - Limit for the number of elements to be printed by showzfreelist
256 current
= Cast(zfirst
, 'void *')
257 while ShowZfreeList
.elts_found
< zlimit
:
258 ShowZfreeList
.elts_found
+= 1
259 znext
= dereference(Cast(current
, 'vm_offset_t *'))
260 backup_ptr
= kern
.GetValueFromAddress((unsigned(Cast(current
, 'vm_offset_t')) + unsigned(zone
.elem_size
) - sizeof('vm_offset_t')), 'vm_offset_t *')
261 backup_val
= dereference(backup_ptr
)
262 n_unobfuscated
= (unsigned(backup_val
) ^
unsigned(kern
.globals.zp_nopoison_cookie
))
263 p_unobfuscated
= (unsigned(backup_val
) ^
unsigned(kern
.globals.zp_poisoned_cookie
))
265 if p_unobfuscated
== unsigned(znext
):
266 poison_str
= "P ({0: <d})".format(ShowZfreeList
.elts_found
- ShowZfreeList
.last_poisoned
)
267 ShowZfreeList
.last_poisoned
= ShowZfreeList
.elts_found
269 if n_unobfuscated
!= unsigned(znext
):
270 poison_str
= "INVALID"
271 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(
272 ShowZfreeList
.elts_found
, unsigned(current
), unsigned(znext
), unsigned(backup_val
), n_unobfuscated
, p_unobfuscated
, poison_str
)
273 if unsigned(znext
) == 0:
275 current
= Cast(znext
, 'void *')
277 @static_var('elts_found',0)
278 @static_var('last_poisoned',0)
279 @lldb_command('showzfreelist')
280 def ShowZfreeList(cmd_args
=None):
281 """ Walk the freelist for a zone, printing out the primary and backup next pointers, the poisoning cookies, and the poisoning status of each element.
282 Usage: showzfreelist <zone> [iterations]
284 Will walk up to 50 elements by default, pass a limit in 'iterations' to override.
287 print ShowZfreeList
.__doc
__
289 ShowZfreeList
.elts_found
= 0
290 ShowZfreeList
.last_poisoned
= 0
292 zone
= kern
.GetValueFromAddress(cmd_args
[0], 'struct zone *')
294 if len(cmd_args
) >= 2:
295 zlimit
= ArgumentStringToInt(cmd_args
[1])
296 ShowZfreeListHeader(zone
)
298 if unsigned(zone
.use_page_list
) == 1:
299 if unsigned(zone
.allows_foreign
) == 1:
300 for free_page_meta
in IterateQueue(zone
.pages
.any_free_foreign
, 'struct zone_page_metadata *', 'pages'):
301 if ShowZfreeList
.elts_found
== zlimit
:
303 zfirst
= Cast(free_page_meta
.elements
, 'void *')
304 if unsigned(zfirst
) != 0:
305 ShowZfreeListChain(zone
, zfirst
, zlimit
)
306 for free_page_meta
in IterateQueue(zone
.pages
.intermediate
, 'struct zone_page_metadata *', 'pages'):
307 if ShowZfreeList
.elts_found
== zlimit
:
309 zfirst
= Cast(free_page_meta
.elements
, 'void *')
310 if unsigned(zfirst
) != 0:
311 ShowZfreeListChain(zone
, zfirst
, zlimit
)
312 for free_page_meta
in IterateQueue(zone
.pages
.all_free
, 'struct zone_page_metadata *', 'pages'):
313 if ShowZfreeList
.elts_found
== zlimit
:
315 zfirst
= Cast(free_page_meta
.elements
, 'void *')
316 if unsigned(zfirst
) != 0:
317 ShowZfreeListChain(zone
, zfirst
, zlimit
)
319 zfirst
= Cast(zone
.free_elements
, 'void *')
320 if unsigned(zfirst
) != 0:
321 ShowZfreeListChain(zone
, zfirst
, zlimit
)
323 if ShowZfreeList
.elts_found
== zlimit
:
324 print "Stopped at {0: <d} elements!".format(zlimit
)
326 print "Found {0: <d} elements!".format(ShowZfreeList
.elts_found
)
328 # EndMacro: showzfreelist
332 @lldb_command('zstack')
333 def Zstack(cmd_args
=None):
334 """ 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>.
335 Usage: zstack <index> [<count>]
337 The suggested usage is to look at indexes below zcurrent and look for common stack traces.
338 The stack trace that occurs the most is probably the cause of the leak. Find the pc of the
339 function calling into zalloc and use the countpcs command to find out how often that pc occurs in the log.
340 The pc occuring in a high percentage of records is most likely the source of the leak.
342 The findoldest command is also useful for leak debugging since it identifies the oldest record
343 in the log, which may indicate the leaker.
348 if int(kern
.globals.log_records
) == 0:
349 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
351 if int(kern
.globals.zlog_btlog
) == 0:
352 print "Zone logging enabled, but zone has not been initialized yet."
356 if len(cmd_args
) >= 2:
357 count
= ArgumentStringToInt(cmd_args
[1])
358 zstack_index
= unsigned(cmd_args
[0])
359 while count
and (zstack_index
!= 0xffffff):
360 zstack_record_offset
= zstack_index
* unsigned(kern
.globals.zlog_btlog
.btrecord_size
)
361 zstack_record
= kern
.GetValueFromAddress(unsigned(kern
.globals.zlog_btlog
.btrecords
) + zstack_record_offset
, 'btlog_record_t *')
362 ShowZStackRecord(zstack_record
, zstack_index
)
363 zstack_index
= zstack_record
.next
370 @lldb_command('findoldest')
371 def FindOldest(cmd_args
=None):
372 """ Zone leak debugging: find and print the oldest record in the log.
374 Once it prints a stack trace, find the pc of the caller above all the zalloc, kalloc and
375 IOKit layers. Then use the countpcs command to see how often this caller has allocated
376 memory. A caller with a high percentage of records in the log is probably the leaker.
378 if int(kern
.globals.log_records
) == 0:
379 print FindOldest
.__doc
__
381 if int(kern
.globals.zlog_btlog
) == 0:
382 print "Zone logging enabled, but zone has not been initialized yet."
384 index
= kern
.globals.zlog_btlog
.head
385 if unsigned(index
) != 0xffffff:
386 print "Oldest record is at log index: {0: <d}".format(index
)
389 print "No Records Present"
391 # EndMacro : findoldest
395 @lldb_command('countpcs')
396 def Countpcs(cmd_args
=None):
397 """ Zone leak debugging: search the log and print a count of all log entries that contain the given <pc>
401 This is useful for verifying a suspected <pc> as being the source of
402 the leak. If a high percentage of the log entries contain the given <pc>, then it's most
403 likely the source of the leak. Note that this command can take several minutes to run.
406 print Countpcs
.__doc
__
408 if int(kern
.globals.log_records
) == 0:
409 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
411 if int(kern
.globals.zlog_btlog
) == 0:
412 print "Zone logging enabled, but zone has not been initialized yet."
415 cpcs_index
= unsigned(kern
.globals.zlog_btlog
.head
)
416 target_pc
= unsigned(kern
.GetValueFromAddress(cmd_args
[0], 'void *'))
418 depth
= unsigned(kern
.globals.zlog_btlog
.btrecord_btdepth
)
420 while cpcs_index
!= 0xffffff:
421 cpcs_record_offset
= cpcs_index
* unsigned(kern
.globals.zlog_btlog
.btrecord_size
)
422 cpcs_record
= kern
.GetValueFromAddress(unsigned(kern
.globals.zlog_btlog
.btrecords
) + cpcs_record_offset
, 'btlog_record_t *')
425 frame_pc
= unsigned(cpcs_record
.bt
[frame
])
426 if frame_pc
== target_pc
:
430 cpcs_index
= cpcs_record
.next
431 print "Occured {0: <d} times in log ({1: <d}{2: <s} of records)".format(found
, (found
* 100)/unsigned(kern
.globals.zlog_btlog
.activecount
), '%')
437 @lldb_command('findelem')
438 def FindElem(cmd_args
=None):
439 """ Zone corruption debugging: search the log and print out the stack traces for all log entries that
440 refer to the given zone element.
441 Usage: findelem <elem addr>
443 When the kernel panics due to a corrupted zone element, get the
444 element address and use this command. This will show you the stack traces of all logged zalloc and
445 zfree operations which tells you who touched the element in the recent past. This also makes
446 double-frees readily apparent.
449 print FindElem
.__doc
__
451 if int(kern
.globals.log_records
) == 0:
452 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
454 if int(kern
.globals.zlog_btlog
) == 0:
455 print "Zone logging enabled, but zone has not been initialized yet."
458 target_element
= unsigned(kern
.GetValueFromAddress(cmd_args
[0], 'void *'))
459 index
= unsigned(kern
.globals.zlog_btlog
.head
)
462 while index
!= 0xffffff:
463 findelem_record_offset
= index
* unsigned(kern
.globals.zlog_btlog
.btrecord_size
)
464 findelem_record
= kern
.GetValueFromAddress(unsigned(kern
.globals.zlog_btlog
.btrecords
) + findelem_record_offset
, 'btlog_record_t *')
465 if unsigned(findelem_record
.element
) == target_element
:
467 if int(findelem_record
.operation
) == prev_op
:
468 print "{0: <s} DOUBLE OP! {1: <s}".format(('*' * 8), ('*' * 8))
469 prev_op
= int(findelem_record
.operation
)
470 index
= findelem_record
.next
476 @lldb_command('btlog_find', "A")
477 def BtlogFind(cmd_args
=None, cmd_options
={}):
478 """ Search the btlog_t for entries corresponding to the given element.
479 Use -A flag to print all entries.
480 Usage: btlog_find <btlog_t> <element>
481 Usage: btlog_find <btlog_t> -A
482 Note: Backtraces will be in chronological order, with oldest entries aged out in FIFO order as needed.
485 raise ArgumentError("Need a btlog_t parameter")
486 btlog
= kern
.GetValueFromAddress(cmd_args
[0], 'btlog_t *')
488 target_elem
= 0xffffff
490 if "-A" in cmd_options
:
493 if not printall
and len(cmd_args
) < 2:
494 raise ArgumentError("<element> is missing in args. Need a search pointer.")
495 target_elem
= unsigned(kern
.GetValueFromAddress(cmd_args
[1], 'void *'))
497 index
= unsigned(btlog
.head
)
499 record_size
= unsigned(btlog
.btrecord_size
)
500 while index
!= 0xffffff:
501 record_offset
= index
* record_size
502 record
= kern
.GetValueFromAddress(unsigned(btlog
.btrecords
) + record_offset
, 'btlog_record_t *')
503 if unsigned(record
.element
) == target_elem
or printall
:
504 print '{0: <s} OP {1: <d} {2: <#0x} {3: <s}\n'.format(('-' * 8), record
.operation
, target_elem
, ('-' * 8))
505 ShowBtlogBacktrace(btlog
.btrecord_btdepth
, record
)
508 if (progress
% 1000) == 0: print '{0: <d} entries searched!\n'.format(progress
)
510 #EndMacro: btlog_find
514 @lldb_command('showzalloc')
515 def ShowZalloc(cmd_args
=None):
516 """ Prints a zallocation from the zallocations array based off its index and prints the associated symbolicated backtrace.
517 Usage: showzalloc <index>
520 print ShowZalloc
.__doc
__
522 if unsigned(kern
.globals.zallocations
) == 0:
523 print "zallocations array not initialized!"
525 zallocation
= kern
.globals.zallocations
[ArgumentStringToInt(cmd_args
[0])]
527 ShowZTrace([str(int(zallocation
.za_trace_index
))])
529 #EndMacro: showzalloc
533 @lldb_command('showztrace')
534 def ShowZTrace(cmd_args
=None):
535 """ Prints the backtrace from the ztraces array at index
536 Usage: showztrace <trace index>
539 print ShowZTrace
.__doc
__
541 if unsigned(kern
.globals.ztraces
) == 0:
542 print "ztraces array not initialized!"
544 ztrace_addr
= kern
.globals.ztraces
[ArgumentStringToInt(cmd_args
[0])]
546 ShowZstackTraceHelper(ztrace_addr
.zt_stack
, ztrace_addr
.zt_depth
)
548 #EndMacro: showztrace
550 #Macro: showztraceaddr
552 @lldb_command('showztraceaddr')
553 def ShowZTraceAddr(cmd_args
=None):
554 """ Prints the struct ztrace passed in.
555 Usage: showztraceaddr <trace address>
558 print ShowZTraceAddr
.__doc
__
560 ztrace_ptr
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ztrace *')
561 print dereference(ztrace_ptr
)
562 ShowZstackTraceHelper(ztrace_ptr
.zt_stack
, ztrace_ptr
.zt_depth
)
564 #EndMacro: showztraceaddr
566 #Macro: showzstacktrace
568 @lldb_command('showzstacktrace')
569 def ShowZstackTrace(cmd_args
=None):
570 """ Routine to print a stacktrace stored by OSBacktrace.
571 Usage: showzstacktrace <saved stacktrace> [size]
573 size is optional, defaults to 15.
576 print ShowZstackTrace
.__doc
__
578 void_ptr_type
= gettype('void *')
579 void_double_ptr_type
= void_ptr_type
.GetPointerType()
580 trace
= kern
.GetValueFromAddress(cmd_args
[0], void_double_ptr_type
)
582 if len(cmd_args
) >= 2:
583 trace_size
= ArgumentStringToInt(cmd_args
[1])
584 ShowZstackTraceHelper(trace
, trace_size
)
586 #EndMacro: showzstacktrace
588 def ShowZstackTraceHelper(stack
, depth
):
589 """ Helper routine for printing a zstack.
591 stack: void *[] - An array of pointers representing the Zstack
592 depth: int - The depth of the ztrace stack
597 while trace_current
< depth
:
598 trace_addr
= stack
[trace_current
]
599 symbol_arr
= kern
.SymbolicateFromAddress(unsigned(trace_addr
))
601 symbol_str
= str(symbol_arr
[0].addr
)
604 print '{0: <#x} {1: <s}'.format(trace_addr
, symbol_str
)
607 #Macro: showtopztrace
609 @lldb_command('showtopztrace')
610 def ShowTopZtrace(cmd_args
=None):
611 """ Shows the ztrace with the biggest size.
612 (According to top_ztrace, not by iterating through the hash table)
614 top_trace
= kern
.globals.top_ztrace
615 print 'Index: {0: <d}'.format((unsigned(top_trace
) - unsigned(kern
.globals.ztraces
)) / sizeof('struct ztrace'))
616 print dereference(top_trace
)
617 ShowZstackTraceHelper(top_trace
.zt_stack
, top_trace
.zt_depth
)
619 #EndMacro: showtopztrace
623 @lldb_command('showzallocs')
624 def ShowZallocs(cmd_args
=None):
625 """ Prints all allocations in the zallocations table
627 if unsigned(kern
.globals.zallocations
) == 0:
628 print "zallocations array not initialized!"
630 print '{0: <5s} {1: <18s} {2: <5s} {3: <15s}'.format('INDEX','ADDRESS','TRACE','SIZE')
632 max_zallocation
= unsigned(kern
.globals.zleak_alloc_buckets
)
634 while current_index
< max_zallocation
:
635 current_zalloc
= kern
.globals.zallocations
[current_index
]
636 if int(current_zalloc
.za_element
) != 0:
637 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
))
638 allocation_count
+= 1
640 print 'Total Allocations: {0: <d}'.format(allocation_count
)
642 #EndMacro: showzallocs
644 #Macro: showzallocsfortrace
646 @lldb_command('showzallocsfortrace')
647 def ShowZallocsForTrace(cmd_args
=None):
648 """ Prints all allocations pointing to the passed in trace's index into ztraces by looking through zallocations table
649 Usage: showzallocsfortrace <trace index>
652 print ShowZallocsForTrace
.__doc
__
654 print '{0: <5s} {1: <18s} {2: <15s}'.format('INDEX','ADDRESS','SIZE')
655 target_index
= ArgumentStringToInt(cmd_args
[0])
657 max_zallocation
= unsigned(kern
.globals.zleak_alloc_buckets
)
659 while current_index
< max_zallocation
:
660 current_zalloc
= kern
.globals.zallocations
[current_index
]
661 if unsigned(current_zalloc
.za_element
) != 0 and (unsigned(current_zalloc
.za_trace_index
) == unsigned(target_index
)):
662 print '{0: <5d} {1: <#018x} {2: <6d}'.format(current_index
, current_zalloc
.za_element
, current_zalloc
.za_size
)
663 allocation_count
+= 1
665 print 'Total Allocations: {0: <d}'.format(allocation_count
)
667 #EndMacro: showzallocsfortrace
671 @lldb_command('showztraces')
672 def ShowZTraces(cmd_args
=None):
673 """ Prints all traces with size > 0
675 ShowZTracesAbove([0])
677 #EndMacro: showztraces
679 #Macro: showztracesabove
681 @lldb_command('showztracesabove')
682 def ShowZTracesAbove(cmd_args
=None):
683 """ Prints all traces with size greater than X
684 Usage: showztracesabove <size>
687 print ShowZTracesAbove
.__doc
__
689 print '{0: <5s} {1: <6s}'.format('INDEX','SIZE')
692 max_ztrace
= unsigned(kern
.globals.zleak_trace_buckets
)
693 while current_index
< max_ztrace
:
694 ztrace_current
= kern
.globals.ztraces
[current_index
]
695 if ztrace_current
.zt_size
> unsigned(cmd_args
[0]):
696 print '{0: <5d} {1: <6d}'.format(current_index
, int(ztrace_current
.zt_size
))
699 print 'Total traces: {0: <d}'.format(ztrace_count
)
701 #EndMacro: showztracesabove
703 #Macro: showztracehistogram
705 @lldb_command('showztracehistogram')
706 def ShowZtraceHistogram(cmd_args
=None):
707 """ Prints the histogram of the ztrace table
709 print '{0: <5s} {1: <9s} {2: <10s}'.format('INDEX','HIT_COUNT','COLLISIONS')
712 max_ztrace
= unsigned(kern
.globals.zleak_trace_buckets
)
713 while current_index
< max_ztrace
:
714 ztrace_current
= kern
.globals.ztraces
[current_index
]
715 if ztrace_current
.zt_hit_count
!= 0:
716 print '{0: <5d} {1: <9d} {2: <10d}'.format(current_index
, ztrace_current
.zt_hit_count
, ztrace_current
.zt_collisions
)
719 print 'Total traces: {0: <d}'.format(ztrace_count
)
721 #EndMacro: showztracehistogram
723 #Macro: showzallochistogram
725 @lldb_command('showzallochistogram')
726 def ShowZallocHistogram(cmd_args
=None):
727 """ Prints the histogram for the zalloc table
729 print '{0: <5s} {1: <9s}'.format('INDEX','HIT_COUNT')
731 zallocation_count
= 0
732 max_ztrace
= unsigned(kern
.globals.zleak_alloc_buckets
)
733 while current_index
< max_ztrace
:
734 zallocation_current
= kern
.globals.zallocations
[current_index
]
735 if zallocation_current
.za_hit_count
!= 0:
736 print '{0: <5d} {1: <9d}'.format(current_index
, zallocation_current
.za_hit_count
)
737 zallocation_count
+= 1
739 print 'Total Allocations: {0: <d}'.format(zallocation_count
)
741 #EndMacro: showzallochistogram
745 @lldb_command('showzstats')
746 def ShowZstats(cmd_args
=None):
747 """ Prints the zone leak detection stats
749 print 'z_alloc_collisions: {0: <d}, z_trace_collisions: {1: <d}'.format(unsigned(kern
.globals.z_alloc_collisions
), unsigned(kern
.globals.z_trace_collisions
))
750 print 'z_alloc_overwrites: {0: <d}, z_trace_overwrites: {1: <d}'.format(unsigned(kern
.globals.z_alloc_overwrites
), unsigned(kern
.globals.z_trace_overwrites
))
751 print 'z_alloc_recorded: {0: <d}, z_trace_recorded: {1: <d}'.format(unsigned(kern
.globals.z_alloc_recorded
), unsigned(kern
.globals.z_trace_recorded
))
753 #EndMacro: showzstats
755 def ShowBtlogBacktrace(depth
, zstack_record
):
756 """ Helper routine for printing a BT Log record backtrace stack.
758 depth:int - The depth of the zstack record
759 zstack_record:btlog_record_t * - A BTLog record
765 if not zstack_record
:
766 print "Zstack record none!"
768 depth_val
= unsigned(depth
)
769 while frame
< depth_val
:
770 frame_pc
= zstack_record
.bt
[frame
]
771 if not frame_pc
or int(frame_pc
) == 0:
773 symbol_arr
= kern
.SymbolicateFromAddress(frame_pc
)
775 symbol_str
= str(symbol_arr
[0].addr
)
778 out_str
+= "{0: <#0x} <{1: <s}>\n".format(frame_pc
, symbol_str
)
782 def ShowZStackRecord(zstack_record
, zstack_index
):
783 """ Helper routine for printing a single zstack record
785 zstack_record:btlog_record_t * - A BTLog record
786 zstack_index:int - Index for the record in the BTLog table
791 if zstack_record
.operation
== 1:
795 out_str
+= "{0: <#0x} : Index {1: <d} {2: <s}\n".format(zstack_record
.element
, zstack_index
, ('-' * 8))
797 ShowBtlogBacktrace(kern
.globals.zlog_btlog
.btrecord_btdepth
, zstack_record
)
801 @lldb_command('showioalloc')
802 def ShowIOAllocations(cmd_args
=None):
803 """ Show some accounting of memory allocated by IOKit allocators. See ioalloccount man page for details.
804 Routine to display a summary of memory accounting allocated by IOKit allocators.
806 print "Instance allocation = {0: <#0x} = {1: d}K".format(kern
.globals.debug_ivars_size
, (kern
.globals.debug_ivars_size
/ 1024))
807 print "Container allocation = {0: <#0x} = {1: d}K".format(kern
.globals.debug_container_malloc_size
, (kern
.globals.debug_container_malloc_size
/ 1024))
808 print "IOMalloc allocation = {0: <#0x} = {1: d}K".format(kern
.globals.debug_iomalloc_size
, (kern
.globals.debug_iomalloc_size
/ 1024))
809 print "Container allocation = {0: <#0x} = {1: d}K".format(kern
.globals.debug_iomallocpageable_size
, (kern
.globals.debug_iomallocpageable_size
/ 1024))
812 # EndMacro: showioalloc
818 @lldb_command('showtaskvme')
819 def ShowTaskVmeHelper(cmd_args
=None):
820 """ Display a summary list of the specified vm_map's entries
821 Usage: showtaskvme <task address> (ex. showtaskvme 0x00ataskptr00 )
823 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
824 ShowTaskVMEntries(task
)
826 @lldb_command('showallvme')
827 def ShowAllVME(cmd_args
=None):
828 """ Routine to print a summary listing of all the vm map entries
829 Go Through each task in system and show the vm info
831 for task
in kern
.tasks
:
832 ShowTaskVMEntries(task
)
834 @lldb_command('showallvm')
835 def ShowAllVM(cmd_args
=None):
836 """ Routine to print a summary listing of all the vm maps
838 for task
in kern
.tasks
:
839 print GetTaskSummary
.header
+ ' ' + GetProcSummary
.header
840 print GetTaskSummary(task
) + ' ' + GetProcSummary(Cast(task
.bsd_info
, 'proc *'))
841 print GetVMMapSummary
.header
842 print GetVMMapSummary(task
.map)
844 @lldb_command("showtaskvm")
845 def ShowTaskVM(cmd_args
=None):
846 """ Display info about the specified task's vm_map
847 syntax: (lldb) showtaskvm <task_ptr>
850 print ShowTaskVM
.__doc
__
852 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
854 print "Unknown arguments."
856 print GetTaskSummary
.header
+ ' ' + GetProcSummary
.header
857 print GetTaskSummary(task
) + ' ' + GetProcSummary(Cast(task
.bsd_info
, 'proc *'))
858 print GetVMMapSummary
.header
859 print GetVMMapSummary(task
.map)
862 @lldb_command('showallvmstats')
863 def ShowAllVMStats(cmd_args
=None):
864 """ Print a summary of vm statistics in a table format
866 vmstats
= lambda:None
867 vmstats
.wired_count
= 0
868 vmstats
.resident_count
= 0
869 vmstats
.resident_max
= 0
873 vmstats
.compressed
= 0
874 vmstats
.compressed_peak
= 0
875 vmstats
.compressed_lifetime
= 0
878 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:}"
879 print hdr_format
.format('pid', 'command', '#ents', 'wired', 'vsize', 'rsize', 'NEW RSIZE', 'max rsize', 'internal', 'external', 'reusable', 'compressed', 'compressed', 'compressed', '')
880 print hdr_format
.format('', '', '', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(current)', '(peak)', '(lifetime)', '')
881 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}"
883 for task
in kern
.tasks
:
884 proc
= Cast(task
.bsd_info
, 'proc *')
885 vmmap
= Cast(task
.map, '_vm_map *')
887 vmstats
.wired_count
= vmmap
.pmap
.stats
.wired_count
;
888 vmstats
.resident_count
= unsigned(vmmap
.pmap
.stats
.resident_count
);
889 vmstats
.resident_max
= vmmap
.pmap
.stats
.resident_max
;
890 vmstats
.internal
= unsigned(vmmap
.pmap
.stats
.internal
);
891 vmstats
.external
= unsigned(vmmap
.pmap
.stats
.external
);
892 vmstats
.reusable
= unsigned(vmmap
.pmap
.stats
.reusable
);
893 vmstats
.compressed
= unsigned(vmmap
.pmap
.stats
.compressed
);
894 vmstats
.compressed_peak
= unsigned(vmmap
.pmap
.stats
.compressed_peak
);
895 vmstats
.compressed_lifetime
= unsigned(vmmap
.pmap
.stats
.compressed_lifetime
);
896 vmstats
.new_resident_count
= vmstats
.internal
+ vmstats
.external
898 if vmstats
.internal
< 0:
900 if vmstats
.external
< 0:
902 if vmstats
.reusable
< 0:
904 if vmstats
.compressed
< 0:
906 if vmstats
.compressed_peak
< 0:
908 if vmstats
.compressed_lifetime
< 0:
910 if vmstats
.new_resident_count
+vmstats
.reusable
!= vmstats
.resident_count
:
913 print entry_format
.format(p
=proc
, m
=vmmap
, vsize
=(unsigned(vmmap
.size
) >> 12), t
=task
, s
=vmstats
)
916 def ShowTaskVMEntries(task
):
917 """ Routine to print out a summary listing of all the entries in a vm_map
919 task - core.value : a object of type 'task *'
923 print "vm_map entries for task " + hex(task
)
924 print GetTaskSummary
.header
925 print GetTaskSummary(task
)
927 print "Task {0: <#020x} has map = 0x0"
929 print GetVMMapSummary
.header
930 print GetVMMapSummary(task
.map)
931 vme_list_head
= task
.map.hdr
.links
932 vme_ptr_type
= GetType('vm_map_entry *')
933 print GetVMEntrySummary
.header
934 for vme
in IterateQueue(vme_list_head
, vme_ptr_type
, "links"):
935 print GetVMEntrySummary(vme
)
938 @lldb_command("showmap")
939 def ShowMap(cmd_args
=None):
940 """ Routine to print out info about the specified vm_map
941 usage: showmap <vm_map>
943 if cmd_args
== None or len(cmd_args
) < 1:
944 print "Invalid argument.", ShowMap
.__doc
__
946 map_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vm_map_t')
947 print GetVMMapSummary
.header
948 print GetVMMapSummary(map_val
)
950 @lldb_command("showmapvme")
951 def ShowMapVME(cmd_args
=None):
952 """Routine to print out info about the specified vm_map and its vm entries
953 usage: showmapvme <vm_map>
955 if cmd_args
== None or len(cmd_args
) < 1:
956 print "Invalid argument.", ShowMap
.__doc
__
958 map_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vm_map_t')
959 print GetVMMapSummary
.header
960 print GetVMMapSummary(map_val
)
961 vme_list_head
= map_val
.hdr
.links
962 vme_ptr_type
= GetType('vm_map_entry *')
963 print GetVMEntrySummary
.header
964 for vme
in IterateQueue(vme_list_head
, vme_ptr_type
, "links"):
965 print GetVMEntrySummary(vme
)
968 @lldb_type_summary(['_vm_map *', 'vm_map_t'])
969 @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"))
970 def GetVMMapSummary(vmmap
):
971 """ Display interesting bits from vm_map struct """
973 format_string
= "{0: <#020x} {1: <#020x} {2: <#020x} {3: >5d} {4: >5d} {5: <#020x} {6: <#020x}"
974 vm_size
= uint64_t(vmmap
.size
).value
976 if vmmap
.pmap
!= 0: resident_pages
= int(vmmap
.pmap
.stats
.resident_count
)
977 out_string
+= format_string
.format(vmmap
, vmmap
.pmap
, vm_size
, vmmap
.hdr
.nentries
, resident_pages
, vmmap
.hint
, vmmap
.first_free
)
980 @lldb_type_summary(['vm_map_entry'])
981 @header("{0: <20s} {1: <20s} {2: <5s} {3: >7s} {4: <20s} {5: <20s}".format("entry", "start", "prot", "#page", "object", "offset"))
982 def GetVMEntrySummary(vme
):
983 """ Display vm entry specific information. """
985 format_string
= "{0: <#020x} {1: <#20x} {2: <1x}{3: <1x}{4: <3s} {5: >7d} {6: <#020x} {7: <#020x}"
986 vme_protection
= int(vme
.protection
)
987 vme_max_protection
= int(vme
.max_protection
)
988 vme_extra_info_str
="SC-Ds"[int(vme
.inheritance
)]
989 if int(vme
.is_sub_map
) != 0 :
990 vme_extra_info_str
+="s"
991 elif int(vme
.needs_copy
) != 0 :
992 vme_extra_info_str
+="n"
993 num_pages
= (unsigned(vme
.links
.end
) - unsigned(vme
.links
.start
)) >> 12
994 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
)
997 # EndMacro: showtaskvme
998 @lldb_command('showmapwired')
999 def ShowMapWired(cmd_args
=None):
1000 """ Routine to print out a summary listing of all the entries with wired pages in a vm_map
1002 if cmd_args
== None or len(cmd_args
) < 1:
1003 print "Invalid argument", ShowMapWired
.__doc
__
1005 map_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vm_map_t')
1008 @lldb_type_summary(['kmod_info_t *'])
1009 @header("{0: <20s} {1: <20s} {2: <20s} {3: >3s} {4: >5s} {5: >20s} {6: <30s}".format('kmod_info', 'address', 'size', 'id', 'refs', 'version', 'name'))
1010 def GetKextSummary(kmod
):
1011 """ returns a string representation of kext information
1014 format_string
= "{0: <#020x} {1: <#020x} {2: <#020x} {3: >3d} {4: >5d} {5: >20s} {6: <30s}"
1015 out_string
+= format_string
.format(kmod
, kmod
.address
, kmod
.size
, kmod
.id, kmod
.reference_count
, kmod
.version
, kmod
.name
)
1018 @lldb_type_summary(['uuid_t'])
1020 def GetUUIDSummary(uuid
):
1021 """ returns a string representation like CA50DA4C-CA10-3246-B8DC-93542489AA26
1023 arr
= Cast(addressof(uuid
), 'uint8_t *')
1026 data
.append(int(arr
[i
]))
1027 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
)
1029 @lldb_command('showallkmods')
1030 def ShowAllKexts(cmd_args
=None):
1031 """Display a summary listing of all loaded kexts (alias: showallkmods)
1033 kmod_val
= kern
.globals.kmod
1034 print "{: <36s} ".format("UUID") + GetKextSummary
.header
1035 kextuuidinfo
= GetKextLoadInformation()
1036 for kval
in IterateLinkedList(kmod_val
, 'next'):
1037 uuid
= "........-....-....-....-............"
1038 kaddr
= unsigned(kval
.address
)
1039 for l
in kextuuidinfo
:
1040 if kaddr
== int(l
[1],16):
1043 print uuid
+ " " + GetKextSummary(kval
)
1045 def GetKextLoadInformation(addr
=0):
1046 """ Extract the kext uuid and load address information from the kernel data structure.
1048 addr - int - optional integer that is the address to search for.
1050 [] - array with each entry of format ( 'UUID', 'Hex Load Address')
1052 # because of <rdar://problem/12683084>, we can't find summaries directly
1053 #addr = hex(addressof(kern.globals.gLoadedKextSummaries.summaries))
1054 baseaddr
= unsigned(kern
.globals.gLoadedKextSummaries
) + 0x10
1055 summaries_begin
= kern
.GetValueFromAddress(baseaddr
, 'OSKextLoadedKextSummary *')
1056 total_summaries
= int(kern
.globals.gLoadedKextSummaries
.numSummaries
)
1057 kext_version
= int(kern
.globals.gLoadedKextSummaries
.version
)
1058 entry_size
= 64 + 16 + 8 + 8 + 8 + 4 + 4
1059 if kext_version
>= 2 :
1060 entry_size
= int(kern
.globals.gLoadedKextSummaries
.entry_size
)
1062 for i
in range(total_summaries
):
1063 tmpaddress
= unsigned(summaries_begin
) + (i
* entry_size
)
1064 current_kext
= kern
.GetValueFromAddress(tmpaddress
, 'OSKextLoadedKextSummary *')
1066 if addr
== unsigned(current_kext
.address
):
1067 retval
.append((GetUUIDSummary(current_kext
.uuid
) , hex(current_kext
.address
), str(current_kext
.name
) ))
1069 retval
.append((GetUUIDSummary(current_kext
.uuid
) , hex(current_kext
.address
), str(current_kext
.name
) ))
1073 lldb_alias('showallkexts', 'showallkmods')
1075 def GetOSKextVersion(version_num
):
1076 """ returns a string of format 1.2.3x from the version_num
1077 params: version_num - int
1080 if version_num
== -1 :
1082 (MAJ_MULT
, MIN_MULT
, REV_MULT
,STAGE_MULT
) = (100000000, 1000000, 10000, 1000)
1083 version
= version_num
1085 vers_major
= version
/ MAJ_MULT
1086 version
= version
- (vers_major
* MAJ_MULT
)
1088 vers_minor
= version
/ MIN_MULT
1089 version
= version
- (vers_minor
* MIN_MULT
)
1091 vers_revision
= version
/ REV_MULT
1092 version
= version
- (vers_revision
* REV_MULT
)
1094 vers_stage
= version
/ STAGE_MULT
1095 version
= version
- (vers_stage
* STAGE_MULT
)
1097 vers_stage_level
= version
1099 out_str
= "%d.%d" % (vers_major
, vers_minor
)
1100 if vers_revision
> 0: out_str
+= ".%d" % vers_revision
1101 if vers_stage
== 1 : out_str
+= "d%d" % vers_stage_level
1102 if vers_stage
== 3 : out_str
+= "a%d" % vers_stage_level
1103 if vers_stage
== 5 : out_str
+= "b%d" % vers_stage_level
1104 if vers_stage
== 6 : out_str
+= "fc%d" % vers_stage_level
1108 @lldb_command('showallknownkmods')
1109 def ShowAllKnownKexts(cmd_args
=None):
1110 """ Display a summary listing of all kexts known in the system.
1111 This is particularly useful to find if some kext was unloaded before this crash'ed state.
1113 kext_count
= int(kern
.globals.sKextsByID
.count
)
1115 kext_dictionary
= kern
.globals.sKextsByID
.dictionary
1116 print "%d kexts in sKextsByID:" % kext_count
1117 print "{0: <20s} {1: <20s} {2: >5s} {3: >20s} {4: <30s}".format('OSKEXT *', 'load_addr', 'id', 'version', 'name')
1118 format_string
= "{0: <#020x} {1: <20s} {2: >5s} {3: >20s} {4: <30s}"
1120 while index
< kext_count
:
1121 kext_dict
= GetObjectAtIndexFromArray(kext_dictionary
, index
)
1122 kext_name
= str(kext_dict
.key
.string
)
1123 osk
= Cast(kext_dict
.value
, 'OSKext *')
1124 if int(osk
.flags
.loaded
) :
1125 load_addr
= "{0: <#020x}".format(osk
.kmod_info
)
1126 id = "{0: >5d}".format(osk
.loadTag
)
1128 load_addr
= "------"
1130 version_num
= unsigned(osk
.version
)
1131 version
= GetOSKextVersion(version_num
)
1132 print format_string
.format(osk
, load_addr
, id, version
, kext_name
)
1137 @lldb_command('showkmodaddr')
1138 def ShowKmodAddr(cmd_args
=[]):
1139 """ Given an address, print the offset and name for the kmod containing it
1140 Syntax: (lldb) showkmodaddr <addr>
1142 if len(cmd_args
) < 1:
1143 raise ArgumentError("Insufficient arguments")
1145 addr
= ArgumentStringToInt(cmd_args
[0])
1146 kmod_val
= kern
.globals.kmod
1147 for kval
in IterateLinkedList(kmod_val
, 'next'):
1148 if addr
>= unsigned(kval
.address
) and addr
<= (unsigned(kval
.address
) + unsigned(kval
.size
)):
1149 print GetKextSummary
.header
1150 print GetKextSummary(kval
) + " offset = {0: #0x}".format((addr
- unsigned(kval
.address
)))
1154 @lldb_command('addkext','F:N:')
1155 def AddKextSyms(cmd_args
=[], cmd_options
={}):
1156 """ Add kext symbols into lldb.
1157 This command finds symbols for a uuid and load the required executable
1159 addkext <uuid> : Load one kext based on uuid. eg. (lldb)addkext 4DD2344C0-4A81-3EAB-BDCF-FEAFED9EB73E
1160 addkext -F <abs/path/to/executable> <load_address> : Load kext executable at specified load address
1161 addkext -N <name> : Load one kext that matches the name provided. eg. (lldb) addkext -N corecrypto
1162 addkext all : Will load all the kext symbols - SLOW
1166 if "-F" in cmd_options
:
1167 exec_path
= cmd_options
["-F"]
1168 exec_full_path
= ResolveFSPath(exec_path
)
1169 if not os
.path
.exists(exec_full_path
):
1170 raise ArgumentError("Unable to resolve {:s}".format(exec_path
))
1172 if not os
.path
.isfile(exec_full_path
):
1173 raise ArgumentError("Path is {:s} not a filepath. \nPlease check that path points to executable.\
1174 \nFor ex. path/to/Symbols/IOUSBFamily.kext/Contents/PlugIns/AppleUSBHub.kext/Contents/MacOS/AppleUSBHub.\
1175 \nNote: LLDB does not support adding kext based on directory paths like gdb used to.".format(exec_path
))
1176 if not os
.access(exec_full_path
, os
.X_OK
):
1177 raise ArgumentError("Path is {:s} not an executable file".format(exec_path
))
1181 slide_value
= cmd_args
[0]
1182 debuglog("loading slide value from user input %s" % cmd_args
[0])
1184 filespec
= lldb
.SBFileSpec(exec_full_path
, False)
1185 print "target modules add %s" % exec_full_path
1186 print lldb_run_command("target modules add %s" % exec_full_path
)
1187 loaded_module
= LazyTarget
.GetTarget().FindModule(filespec
)
1188 if loaded_module
.IsValid():
1189 uuid_str
= loaded_module
.GetUUIDString()
1190 debuglog("added module %s with uuid %s" % (exec_full_path
, uuid_str
))
1191 if slide_value
is None:
1192 all_kexts_info
= GetKextLoadInformation()
1193 for k
in all_kexts_info
:
1195 if k
[0].lower() == uuid_str
.lower():
1197 debuglog("found the slide %s for uuid %s" % (k
[1], k
[0]))
1199 if slide_value
is None:
1200 raise ArgumentError("Unable to find load address for module described at %s " % exec_full_path
)
1201 load_cmd
= "target modules load --file %s --slide %s" % (exec_full_path
, str(slide_value
))
1203 print lldb_run_command(load_cmd
)
1204 kern
.symbolicator
= None
1207 all_kexts_info
= GetKextLoadInformation()
1209 if "-N" in cmd_options
:
1210 kext_name
= cmd_options
["-N"]
1211 kext_name_matches
= GetLongestMatchOption(kext_name
, [str(x
[2]) for x
in all_kexts_info
], True)
1212 if len(kext_name_matches
) != 1:
1213 print "Ambiguous match for name: {:s}".format(kext_name
)
1214 if len(kext_name_matches
) > 0:
1215 print "Options are:\n\t" + "\n\t".join(kext_name_matches
)
1217 debuglog("matched the kext to name %s and uuid %s" % (kext_name_matches
[0], kext_name
))
1218 for x
in all_kexts_info
:
1219 if kext_name_matches
[0] == x
[2]:
1220 cur_uuid
= x
[0].lower()
1221 print "Fetching dSYM for {:s}".format(cur_uuid
)
1222 info
= dsymForUUID(cur_uuid
)
1223 if info
and 'DBGSymbolRichExecutable' in info
:
1224 print "Adding dSYM ({0:s}) for {1:s}".format(cur_uuid
, info
['DBGSymbolRichExecutable'])
1225 addDSYM(cur_uuid
, info
)
1226 loadDSYM(cur_uuid
, int(x
[1],16))
1228 print "Failed to get symbol info for {:s}".format(cur_uuid
)
1230 kern
.symbolicator
= None
1233 if len(cmd_args
) < 1:
1234 raise ArgumentError("No arguments specified.")
1236 uuid
= cmd_args
[0].lower()
1238 load_all_kexts
= False
1240 load_all_kexts
= True
1242 if not load_all_kexts
and len(uuid_regex
.findall(uuid
)) == 0:
1243 raise ArgumentError("Unknown argument {:s}".format(uuid
))
1245 for k_info
in all_kexts_info
:
1246 cur_uuid
= k_info
[0].lower()
1247 if load_all_kexts
or (uuid
== cur_uuid
):
1248 print "Fetching dSYM for %s" % cur_uuid
1249 info
= dsymForUUID(cur_uuid
)
1250 if info
and 'DBGSymbolRichExecutable' in info
:
1251 print "Adding dSYM (%s) for %s" % (cur_uuid
, info
['DBGSymbolRichExecutable'])
1252 addDSYM(cur_uuid
, info
)
1253 loadDSYM(cur_uuid
, int(k_info
[1],16))
1255 print "Failed to get symbol info for %s" % cur_uuid
1257 kern
.symbolicator
= None
1262 lldb_alias('showkmod', 'showkmodaddr')
1263 lldb_alias('showkext', 'showkmodaddr')
1264 lldb_alias('showkextaddr', 'showkmodaddr')
1266 @lldb_type_summary(['mount *'])
1267 @header("{0: <20s} {1: <20s} {2: <20s} {3: <12s} {4: <12s} {5: <12s} {6: >6s} {7: <30s} {8: <35s}".format('volume(mp)', 'mnt_data', 'mnt_devvp', 'flag', 'kern_flag', 'lflag', 'type', 'mnton', 'mntfrom'))
1268 def GetMountSummary(mount
):
1269 """ Display a summary of mount on the system
1271 out_string
= ("{mnt: <#020x} {mnt.mnt_data: <#020x} {mnt.mnt_devvp: <#020x} {mnt.mnt_flag: <#012x} " +
1272 "{mnt.mnt_kern_flag: <#012x} {mnt.mnt_lflag: <#012x} {vfs.f_fstypename: >6s} " +
1273 "{vfs.f_mntonname: <30s} {vfs.f_mntfromname: <35s}").format(mnt
=mount
, vfs
=mount
.mnt_vfsstat
)
1276 @lldb_command('showallmounts')
1277 def ShowAllMounts(cmd_args
=None):
1278 """ Print all mount points
1280 mntlist
= kern
.globals.mountlist
1281 print GetMountSummary
.header
1282 for mnt
in IterateTAILQ_HEAD(mntlist
, 'mnt_list'):
1283 print GetMountSummary(mnt
)
1286 lldb_alias('ShowAllVols', 'showallmounts')
1288 @lldb_command('systemlog')
1289 def ShowSystemLog(cmd_args
=None):
1290 """ Display the kernel's printf ring buffer """
1291 msgbufp
= kern
.globals.msgbufp
1292 msg_size
= int(msgbufp
.msg_size
)
1293 msg_bufx
= int(msgbufp
.msg_bufx
)
1294 msg_bufr
= int(msgbufp
.msg_bufr
)
1295 msg_bufc
= msgbufp
.msg_bufc
1296 msg_bufc_data
= msg_bufc
.GetSBValue().GetPointeeData(0, msg_size
)
1298 # the buffer is circular; start at the write pointer to end,
1299 # then from beginning to write pointer
1301 err
= lldb
.SBError()
1302 for i
in range(msg_bufx
, msg_size
) + range(0, msg_bufx
) :
1304 cbyte
= msg_bufc_data
.GetUnsignedInt8(err
, i
)
1305 if not err
.Success() :
1306 raise ValueError("Failed to read character at offset " + i
+ ": " + err
.GetCString())
1321 @static_var('output','')
1322 def _GetVnodePathName(vnode
, vnodename
):
1323 """ Internal function to get vnode path string from vnode structure.
1327 returns Nothing. The output will be stored in the static variable.
1331 if int(vnode
.v_flag
) & 0x1 and int(hex(vnode
.v_mount
), 16) !=0:
1332 if int(vnode
.v_mount
.mnt_vnodecovered
):
1333 _GetVnodePathName(vnode
.v_mount
.mnt_vnodecovered
, str(vnode
.v_mount
.mnt_vnodecovered
.v_name
) )
1335 _GetVnodePathName(vnode
.v_parent
, str(vnode
.v_parent
.v_name
))
1336 _GetVnodePathName
.output
+= "/%s" % vnodename
1338 def GetVnodePath(vnode
):
1339 """ Get string representation of the vnode
1340 params: vnodeval - value representing vnode * in the kernel
1341 return: str - of format /path/to/something
1345 if (int(vnode
.v_flag
) & 0x000001) and int(hex(vnode
.v_mount
), 16) != 0 and (int(vnode
.v_mount
.mnt_flag
) & 0x00004000) :
1348 _GetVnodePathName
.output
= ''
1349 if abs(vnode
.v_name
) != 0:
1350 _GetVnodePathName(vnode
, str(vnode
.v_name
))
1351 out_str
+= _GetVnodePathName
.output
1353 out_str
+= 'v_name = NULL'
1354 _GetVnodePathName
.output
= ''
1358 @lldb_command('showvnodepath')
1359 def ShowVnodePath(cmd_args
=None):
1360 """ Prints the path for a vnode
1361 usage: showvnodepath <vnode>
1363 if cmd_args
!= None and len(cmd_args
) > 0 :
1364 vnode_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vnode *')
1366 print GetVnodePath(vnode_val
)
1369 # Macro: showvnodedev
1370 def GetVnodeDevInfo(vnode
):
1371 """ Internal function to get information from the device type vnodes
1372 params: vnode - value representing struct vnode *
1373 return: str - formatted output information for block and char vnode types passed as param
1375 vnodedev_output
= ""
1376 vblk_type
= GetEnumValue('vtype::VBLK')
1377 vchr_type
= GetEnumValue('vtype::VCHR')
1378 if (vnode
.v_type
== vblk_type
) or (vnode
.v_type
== vchr_type
):
1379 devnode
= Cast(vnode
.v_data
, 'devnode_t *')
1380 devnode_dev
= devnode
.dn_typeinfo
.dev
1381 devnode_major
= (devnode_dev
>> 24) & 0xff
1382 devnode_minor
= devnode_dev
& 0x00ffffff
1384 # boilerplate device information for a vnode
1385 vnodedev_output
+= "Device Info:\n\t vnode:\t\t{:#x}".format(vnode
)
1386 vnodedev_output
+= "\n\t type:\t\t"
1387 if (vnode
.v_type
== vblk_type
):
1388 vnodedev_output
+= "VBLK"
1389 if (vnode
.v_type
== vchr_type
):
1390 vnodedev_output
+= "VCHR"
1391 vnodedev_output
+= "\n\t name:\t\t{:<s}".format(vnode
.v_name
)
1392 vnodedev_output
+= "\n\t major, minor:\t{:d},{:d}".format(devnode_major
, devnode_minor
)
1393 vnodedev_output
+= "\n\t mode\t\t0{:o}".format(unsigned(devnode
.dn_mode
))
1394 vnodedev_output
+= "\n\t owner (u,g):\t{:d} {:d}".format(devnode
.dn_uid
, devnode
.dn_gid
)
1396 # decode device specific data
1397 vnodedev_output
+= "\nDevice Specific Information:\t"
1398 if (vnode
.v_type
== vblk_type
):
1399 vnodedev_output
+= "Sorry, I do not know how to decode block devices yet!"
1400 vnodedev_output
+= "\nMaybe you can write me!"
1402 if (vnode
.v_type
== vchr_type
):
1403 # Device information; this is scanty
1405 if (devnode_major
> 42) or (devnode_major
< 0):
1406 vnodedev_output
+= "Invalid major #\n"
1407 # static assignments in conf
1408 elif (devnode_major
== 0):
1409 vnodedev_output
+= "Console mux device\n"
1410 elif (devnode_major
== 2):
1411 vnodedev_output
+= "Current tty alias\n"
1412 elif (devnode_major
== 3):
1413 vnodedev_output
+= "NULL device\n"
1414 elif (devnode_major
== 4):
1415 vnodedev_output
+= "Old pty slave\n"
1416 elif (devnode_major
== 5):
1417 vnodedev_output
+= "Old pty master\n"
1418 elif (devnode_major
== 6):
1419 vnodedev_output
+= "Kernel log\n"
1420 elif (devnode_major
== 12):
1421 vnodedev_output
+= "Memory devices\n"
1422 # Statically linked dynamic assignments
1423 elif unsigned(kern
.globals.cdevsw
[devnode_major
].d_open
) == unsigned(kern
.GetLoadAddressForSymbol('ptmx_open')):
1424 vnodedev_output
+= "Cloning pty master not done\n"
1425 #GetVnodeDevCpty(devnode_major, devnode_minor)
1426 elif unsigned(kern
.globals.cdevsw
[devnode_major
].d_open
) == unsigned(kern
.GetLoadAddressForSymbol('ptsd_open')):
1427 vnodedev_output
+= "Cloning pty slave not done\n"
1428 #GetVnodeDevCpty(devnode_major, devnode_minor)
1430 vnodedev_output
+= "RESERVED SLOT\n"
1432 vnodedev_output
+= "{:#x} is not a device".format(vnode
)
1433 return vnodedev_output
1435 @lldb_command('showvnodedev')
1436 def ShowVnodeDev(cmd_args
=None):
1437 """ Routine to display details of all vnodes of block and character device types
1438 Usage: showvnodedev <address of vnode>
1441 print "No arguments passed"
1442 print ShowVnodeDev
.__doc
__
1444 vnode_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vnode *')
1446 print "unknown arguments:", str(cmd_args
)
1448 print GetVnodeDevInfo(vnode_val
)
1450 # EndMacro: showvnodedev
1452 # Macro: showvnodelocks
1453 def GetVnodeLock(lockf
):
1454 """ Internal function to get information from the given advisory lock
1455 params: lockf - value representing v_lockf member in struct vnode *
1456 return: str - formatted output information for the advisory lock
1458 vnode_lock_output
= ''
1459 lockf_flags
= lockf
.lf_flags
1460 lockf_type
= lockf
.lf_type
1461 if lockf_flags
& 0x20:
1462 vnode_lock_output
+= ("{: <8s}").format('flock')
1463 if lockf_flags
& 0x40:
1464 vnode_lock_output
+= ("{: <8s}").format('posix')
1465 if lockf_flags
& 0x80:
1466 vnode_lock_output
+= ("{: <8s}").format('prov')
1467 if lockf_flags
& 0x10:
1468 vnode_lock_output
+= ("{: <4s}").format('W')
1470 vnode_lock_output
+= ("{: <4s}").format('.')
1472 # POSIX file vs advisory range locks
1473 if lockf_flags
& 0x40:
1474 lockf_proc
= Cast(lockf
.lf_id
, 'proc *')
1475 vnode_lock_output
+= ("PID {: <18d}").format(lockf_proc
.p_pid
)
1477 vnode_lock_output
+= ("ID {: <#019x}").format(int(lockf
.lf_id
))
1481 vnode_lock_output
+= ("{: <12s}").format('shared')
1484 vnode_lock_output
+= ("{: <12s}").format('exclusive')
1487 vnode_lock_output
+= ("{: <12s}").format('unlock')
1489 vnode_lock_output
+= ("{: <12s}").format('unknown')
1491 # start and stop values
1492 vnode_lock_output
+= ("{: #018x} ..").format(lockf
.lf_start
)
1493 vnode_lock_output
+= ("{: #018x}\n").format(lockf
.lf_end
)
1494 return vnode_lock_output
1496 @header("{0: <3s} {1: <7s} {2: <3s} {3: <21s} {4: <11s} {5: ^19s} {6: ^17s}".format('*', 'type', 'W', 'held by', 'lock type', 'start', 'end'))
1497 def GetVnodeLocksSummary(vnode
):
1498 """ Internal function to get summary of advisory locks for the given vnode
1499 params: vnode - value representing the vnode object
1500 return: str - formatted output information for the summary of advisory locks
1504 lockf_list
= vnode
.v_lockf
1505 for lockf_itr
in IterateLinkedList(lockf_list
, 'lf_next'):
1506 out_str
+= ("{: <4s}").format('H')
1507 out_str
+= GetVnodeLock(lockf_itr
)
1508 lockf_blocker
= lockf_itr
.lf_blkhd
.tqh_first
1509 while lockf_blocker
:
1510 out_str
+= ("{: <4s}").format('>')
1511 out_str
+= GetVnodeLock(lockf_blocker
)
1512 lockf_blocker
= lockf_blocker
.lf_block
.tqe_next
1515 @lldb_command('showvnodelocks')
1516 def ShowVnodeLocks(cmd_args
=None):
1517 """ Routine to display list of advisory record locks for the given vnode address
1518 Usage: showvnodelocks <address of vnode>
1521 print "No arguments passed"
1522 print ShowVnodeLocks
.__doc
__
1524 vnode_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vnode *')
1526 print "unknown arguments:", str(cmd_args
)
1528 print GetVnodeLocksSummary
.header
1529 print GetVnodeLocksSummary(vnode_val
)
1531 # EndMacro: showvnodelocks
1533 # Macro: showproclocks
1535 @lldb_command('showproclocks')
1536 def ShowProcLocks(cmd_args
=None):
1537 """ Routine to display list of advisory record locks for the given process
1538 Usage: showproclocks <address of proc>
1541 print "No arguments passed"
1542 print ShowProcLocks
.__doc
__
1544 proc
= kern
.GetValueFromAddress(cmd_args
[0], 'proc *')
1546 print "unknown arguments:", str(cmd_args
)
1549 proc_filedesc
= proc
.p_fd
1550 fd_lastfile
= proc_filedesc
.fd_lastfile
1551 fd_ofiles
= proc_filedesc
.fd_ofiles
1554 while count
<= fd_lastfile
:
1555 if fd_ofiles
[count
]:
1556 fglob
= fd_ofiles
[count
].f_fglob
1557 fo_type
= fglob
.fg_ops
.fo_type
1559 fg_data
= fglob
.fg_data
1560 fg_vnode
= Cast(fg_data
, 'vnode *')
1561 name
= fg_vnode
.v_name
1562 lockf_itr
= fg_vnode
.v_lockf
1565 print GetVnodeLocksSummary
.header
1567 out_str
+= ("\n( fd {:d}, name ").format(count
)
1569 out_str
+= "(null) )\n"
1571 out_str
+= "{:s} )\n".format(name
)
1573 print GetVnodeLocksSummary(fg_vnode
)
1575 print "\n{0: d} total locks for {1: #018x}".format(seen
, proc
)
1577 # EndMacro: showproclocks
1579 @lldb_type_summary(['vnode_t', 'vnode *'])
1580 @header("{0: <20s} {1: >8s} {2: >8s} {3: <20s} {4: <6s} {5: <20s} {6: <6s} {7: <35s}".format('vnode', 'usecount', 'iocount', 'v_data', 'vtype', 'parent', 'mapped', 'name'))
1581 def GetVnodeSummary(vnode
):
1582 """ Get a summary of important information out of vnode
1585 format_string
= "{0: <#020x} {1: >8d} {2: >8d} {3: <#020x} {4: <6s} {5: <#020x} {6: <6s} {7: <35s}"
1586 usecount
= int(vnode
.v_usecount
)
1587 iocount
= int(vnode
.v_iocount
)
1588 v_data_ptr
= int(hex(vnode
.v_data
), 16)
1589 vtype
= int(vnode
.v_type
)
1590 vtype_str
= "%d" % vtype
1591 vnode_types
= ['VNON', 'VREG', 'VDIR', 'VBLK', 'VCHR', 'VLNK', 'VSOCK', 'VFIFO', 'VBAD', 'VSTR', 'VCPLX'] # see vnode.h for enum type definition
1592 if vtype
>= 0 and vtype
< len(vnode_types
):
1593 vtype_str
= vnode_types
[vtype
]
1594 parent_ptr
= int(hex(vnode
.v_parent
), 16)
1595 name_ptr
= int(hex(vnode
.v_name
), 16)
1598 name
= str(vnode
.v_name
)
1599 elif int(vnode
.v_tag
) == 16 :
1600 cnode
= Cast(vnode
.v_data
, 'cnode *')
1601 name
= "hfs: %s" % str( Cast(cnode
.c_desc
.cd_nameptr
, 'char *'))
1603 if (vtype
== 1) and (vnode
.v_un
.vu_ubcinfo
!= 0):
1604 # Check to see if vnode is mapped/unmapped
1605 if (vnode
.v_un
.vu_ubcinfo
.ui_flags
& 0x8) != 0:
1609 out_str
+= format_string
.format(vnode
, usecount
, iocount
, v_data_ptr
, vtype_str
, parent_ptr
, mapped
, name
)
1612 @lldb_command('showallvnodes')
1613 def ShowAllVnodes(cmd_args
=None):
1614 """ Display info about all vnodes
1616 mntlist
= kern
.globals.mountlist
1617 print GetVnodeSummary
.header
1618 for mntval
in IterateTAILQ_HEAD(mntlist
, 'mnt_list'):
1619 for vnodeval
in IterateTAILQ_HEAD(mntval
.mnt_vnodelist
, 'v_mntvnodes'):
1620 print GetVnodeSummary(vnodeval
)
1623 @lldb_command('showvnode')
1624 def ShowVnode(cmd_args
=None):
1625 """ Display info about one vnode
1626 usage: showvnode <vnode>
1628 if cmd_args
== None or len(cmd_args
) < 1:
1629 print "Please provide valid vnode argument. Type help showvnode for help."
1631 vnodeval
= kern
.GetValueFromAddress(cmd_args
[0],'vnode *')
1632 print GetVnodeSummary
.header
1633 print GetVnodeSummary(vnodeval
)
1635 @lldb_command('showvolvnodes')
1636 def ShowVolVnodes(cmd_args
=None):
1637 """ Display info about all vnodes of a given mount_t
1639 if cmd_args
== None or len(cmd_args
) < 1:
1640 print "Please provide a valide mount_t argument. Try 'help showvolvnodes' for help"
1642 mntval
= kern
.GetValueFromAddress(cmd_args
[0], 'mount_t')
1643 print GetVnodeSummary
.header
1644 for vnodeval
in IterateTAILQ_HEAD(mntval
.mnt_vnodelist
, 'v_mntvnodes'):
1645 print GetVnodeSummary(vnodeval
)
1648 @lldb_command('showvolbusyvnodes')
1649 def ShowVolBusyVnodes(cmd_args
=None):
1650 """ Display info about busy (iocount!=0) vnodes of a given mount_t
1652 if cmd_args
== None or len(cmd_args
) < 1:
1653 print "Please provide a valide mount_t argument. Try 'help showvolbusyvnodes' for help"
1655 mntval
= kern
.GetValueFromAddress(cmd_args
[0], 'mount_t')
1656 print GetVnodeSummary
.header
1657 for vnodeval
in IterateTAILQ_HEAD(mntval
.mnt_vnodelist
, 'v_mntvnodes'):
1658 if int(vnodeval
.v_iocount
) != 0:
1659 print GetVnodeSummary(vnodeval
)
1661 @lldb_command('showallbusyvnodes')
1662 def ShowAllBusyVnodes(cmd_args
=None):
1663 """ Display info about all busy (iocount!=0) vnodes
1665 mntlistval
= kern
.globals.mountlist
1666 for mntval
in IterateTAILQ_HEAD(mntlistval
, 'mnt_list'):
1667 ShowVolBusyVnodes([hex(mntval
)])
1669 @lldb_command('print_vnode')
1670 def PrintVnode(cmd_args
=None):
1671 """ Prints out the fields of a vnode struct
1672 Usage: print_vnode <vnode>
1675 print "Please provide valid vnode argument. Type help print_vnode for help."
1679 @lldb_command('showworkqvnodes')
1680 def ShowWorkqVnodes(cmd_args
=None):
1681 """ Print the vnode worker list
1682 Usage: showworkqvnodes <struct mount *>
1685 print "Please provide valid mount argument. Type help showworkqvnodes for help."
1688 mp
= kern
.GetValueFromAddress(cmd_args
[0], 'mount *')
1689 vp
= Cast(mp
.mnt_workerqueue
.tqh_first
, 'vnode *')
1690 print GetVnodeSummary
.header
1692 print GetVnodeSummary(vp
)
1693 vp
= vp
.v_mntvnodes
.tqe_next
1695 @lldb_command('shownewvnodes')
1696 def ShowNewVnodes(cmd_args
=None):
1697 """ Print the new vnode list
1698 Usage: shownewvnodes <struct mount *>
1701 print "Please provide valid mount argument. Type help shownewvnodes for help."
1703 mp
= kern
.GetValueFromAddress(cmd_args
[0], 'mount *')
1704 vp
= Cast(mp
.mnt_newvnodes
.tqh_first
, 'vnode *')
1705 print GetVnodeSummary
.header
1707 print GetVnodeSummary(vp
)
1708 vp
= vp
.v_mntvnodes
.tqe_next
1711 @lldb_command('showprocvnodes')
1712 def ShowProcVnodes(cmd_args
=None):
1713 """ Routine to print out all the open fds which are vnodes in a process
1714 Usage: showprocvnodes <proc *>
1717 print "Please provide valid proc argument. Type help showprocvnodes for help."
1719 procptr
= kern
.GetValueFromAddress(cmd_args
[0], 'proc *')
1720 fdptr
= Cast(procptr
.p_fd
, 'filedesc *')
1721 if int(fdptr
.fd_cdir
) != 0:
1722 print '{0: <25s}\n{1: <s}\n{2: <s}'.format('Current Working Directory:', GetVnodeSummary
.header
, GetVnodeSummary(fdptr
.fd_cdir
))
1723 if int(fdptr
.fd_rdir
) != 0:
1724 print '{0: <25s}\n{1: <s}\n{2: <s}'.format('Current Root Directory:', GetVnodeSummary
.header
, GetVnodeSummary(fdptr
.fd_rdir
))
1726 print '\n' + '{0: <5s} {1: <7s}'.format('fd', 'flags') + GetVnodeSummary
.header
1727 # Hack to get around <rdar://problem/12879494> llb fails to cast addresses to double pointers
1728 fpptr
= Cast(fdptr
.fd_ofiles
, 'fileproc *')
1729 while count
< fdptr
.fd_nfiles
:
1730 fpp
= dereference(fpptr
)
1731 fproc
= Cast(fpp
, 'fileproc *')
1733 fglob
= dereference(fproc
).f_fglob
1735 if (int(fglob
) != 0) and (int(fglob
.fg_ops
.fo_type
) == 1):
1736 if (fdptr
.fd_ofileflags
[count
] & 1): flags
+= 'E'
1737 if (fdptr
.fd_ofileflags
[count
] & 2): flags
+= 'F'
1738 if (fdptr
.fd_ofileflags
[count
] & 4): flags
+= 'R'
1739 if (fdptr
.fd_ofileflags
[count
] & 8): flags
+= 'C'
1740 print '{0: <5d} {1: <7s}'.format(count
, flags
) + GetVnodeSummary(Cast(fglob
.fg_data
, 'vnode *'))
1742 fpptr
= kern
.GetValueFromAddress(int(fpptr
) + kern
.ptrsize
,'fileproc *')
1744 @lldb_command('showallprocvnodes')
1745 def ShowAllProcVnodes(cmd_args
=None):
1746 """ Routine to print out all the open fds which are vnodes
1749 procptr
= Cast(kern
.globals.allproc
.lh_first
, 'proc *')
1750 while procptr
and int(procptr
) != 0:
1751 print '{:<s}'.format("=" * 106)
1752 print GetProcInfo(procptr
)
1753 ShowProcVnodes([int(procptr
)])
1754 procptr
= procptr
.p_list
.le_next
1756 @xnudebug_test('test_vnode')
1757 def TestShowAllVnodes(kernel_target
, config
, lldb_obj
, isConnected
):
1758 """ Test the functionality of vnode related commands
1764 print "Target is not connected. Cannot test memstats"
1766 res
= lldb
.SBCommandReturnObject()
1767 lldb_obj
.debugger
.GetCommandInterpreter().HandleCommand("showallvnodes", res
)
1768 result
= res
.GetOutput()
1769 if len(result
.split("\n")) > 2 and result
.find('VREG') != -1 and len(result
.splitlines()[2].split()) > 5:
1775 @lldb_type_summary(['_lck_grp_ *'])
1776 def GetMutexEntry(mtxg
):
1777 """ Summarize a mutex group entry with important information.
1779 mtxg: value - obj representing a mutex group in kernel
1781 out_string - summary of the mutex group
1785 if kern
.ptrsize
== 8:
1786 format_string
= '{0:#018x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1788 format_string
= '{0:#010x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1790 if mtxg
.lck_grp_mtxcnt
:
1791 out_string
+= format_string
.format(mtxg
, mtxg
.lck_grp_mtxcnt
,mtxg
.lck_grp_stat
.lck_grp_mtx_stat
.lck_grp_mtx_util_cnt
,
1792 mtxg
.lck_grp_stat
.lck_grp_mtx_stat
.lck_grp_mtx_miss_cnt
,
1793 mtxg
.lck_grp_stat
.lck_grp_mtx_stat
.lck_grp_mtx_wait_cnt
, mtxg
.lck_grp_name
)
1796 @lldb_command('showallmtx')
1797 def ShowAllMtx(cmd_args
=None):
1798 """ Routine to print a summary listing of all mutexes
1801 if kern
.ptrsize
== 8:
1802 hdr_format
= '{:<18s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
1804 hdr_format
= '{:<10s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
1806 print hdr_format
.format('LCK GROUP', 'CNT', 'UTIL', 'MISS', 'WAIT', 'NAME')
1808 mtxgrp_queue_head
= kern
.globals.lck_grp_queue
1809 mtxgrp_ptr_type
= GetType('_lck_grp_ *')
1811 for mtxgrp_ptr
in IterateQueue(mtxgrp_queue_head
, mtxgrp_ptr_type
, "lck_grp_link"):
1812 print GetMutexEntry(mtxgrp_ptr
)
1814 # EndMacro: showallmtx
1816 # Macro: showallrwlck
1817 @lldb_type_summary(['_lck_grp_ *'])
1818 def GetRWLEntry(rwlg
):
1819 """ Summarize a reader writer lock group with important information.
1821 rwlg: value - obj representing a reader writer lock group in kernel
1823 out_string - summary of the reader writer lock group
1827 if kern
.ptrsize
== 8:
1828 format_string
= '{0:#018x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1830 format_string
= '{0:#010x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1832 if rwlg
.lck_grp_rwcnt
:
1833 out_string
+= format_string
.format(rwlg
, rwlg
.lck_grp_rwcnt
,rwlg
.lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_util_cnt
,
1834 rwlg
.lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
,
1835 rwlg
.lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_wait_cnt
, rwlg
.lck_grp_name
)
1838 @lldb_command('showallrwlck')
1839 def ShowAllRWLck(cmd_args
=None):
1840 """ Routine to print a summary listing of all read/writer locks
1842 if kern
.ptrsize
== 8:
1843 hdr_format
= '{:<18s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
1845 hdr_format
= '{:<10s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
1847 print hdr_format
.format('LCK GROUP', 'CNT', 'UTIL', 'MISS', 'WAIT', 'NAME')
1849 rwlgrp_queue_head
= kern
.globals.lck_grp_queue
1850 rwlgrp_ptr_type
= GetType('_lck_grp_ *')
1851 for rwlgrp_ptr
in IterateQueue(rwlgrp_queue_head
, rwlgrp_ptr_type
, "lck_grp_link"):
1852 print GetRWLEntry(rwlgrp_ptr
)
1854 # EndMacro: showallrwlck
1856 #Macro: showbootermemorymap
1857 @lldb_command('showbootermemorymap')
1858 def ShowBooterMemoryMap(cmd_args
=None):
1859 """ Prints out the phys memory map from kernelBootArgs
1860 Supported only on x86_64
1862 if kern
.arch
== 'x86_64':
1863 voffset
= unsigned(0xFFFFFF8000000000)
1865 print "showbootermemorymap not supported on this architecture"
1888 boot_args
= kern
.globals.kernelBootArgs
1889 msize
= boot_args
.MemoryMapDescriptorSize
1890 mcount
= (boot_args
.MemoryMapSize
) / unsigned(msize
)
1892 out_string
+= "{0: <12s} {1: <19s} {2: <19s} {3: <19s} {4: <10s}\n".format("Type", "Physical Start", "Number of Pages", "Virtual Start", "Attributes")
1896 mptr
= kern
.GetValueFromAddress(unsigned(boot_args
.MemoryMap
) + voffset
+ unsigned(i
*msize
), 'EfiMemoryRange *')
1897 mtype
= unsigned(mptr
.Type
)
1898 if mtype
in memtype_dict
:
1899 out_string
+= "{0: <12s}".format(memtype_dict
[mtype
])
1901 out_string
+= "{0: <12s}".format("UNKNOWN")
1903 if mptr
.VirtualStart
== 0:
1904 out_string
+= "{0: #019x} {1: #019x} {2: <19s} {3: #019x}\n".format(mptr
.PhysicalStart
, mptr
.NumberOfPages
, ' '*19, mptr
.Attribute
)
1906 out_string
+= "{0: #019x} {1: #019x} {2: #019x} {3: #019x}\n".format(mptr
.PhysicalStart
, mptr
.NumberOfPages
, mptr
.VirtualStart
, mptr
.Attribute
)
1910 #EndMacro: showbootermemorymap