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