2 """ Please make sure you read the README file COMPLETELY BEFORE reading anything below.
3 It is very critical that you read coding guidelines in Section E in README file.
13 from ctypes
import c_int64
15 def vm_unpack_pointer(packed
, params
, type_str
= 'void *'):
16 """ Unpack a pointer packed with VM_PACK_POINTER()
18 packed - value : The packed pointer value
19 params - value : The packing parameters of type vm_packing_params_t
20 type_str - str : The type to cast the unpacked pointer into
24 if params
.vmpp_base_relative
:
25 addr
= unsigned(packed
) << int(params
.vmpp_shift
)
26 if addr
: addr
+= int(params
.vmpp_base
)
28 bits
= int(params
.vmpp_bits
)
29 shift
= int(params
.vmpp_shift
)
30 addr
= c_int64(unsigned(packed
) << (64 - bits
)).value
31 addr
>>= 64 - bits
- shift
32 return kern
.GetValueFromAddress(addr
, type_str
)
34 def IterateZPerCPU(root
, element_type
):
35 """ Iterates over a percpu variable
37 root - value : Value object for per-cpu variable
38 element_type - str : Type of element
42 pagesize
= kern
.globals.page_size
43 mangle
= 1 << (8 * kern
.ptrsize
- 1)
44 for i
in range(0, kern
.globals.zpercpu_early_count
):
45 yield kern
.GetValueFromAddress((int(root
) | mangle
) + i
* pagesize
, element_type
)
47 @lldb_command('showzpcpu', "S")
48 def ShowZPerCPU(cmd_args
=None, cmd_options
={}):
49 """ Routine to show per-cpu zone allocated variables
51 Usage: showzpcpu [-S] expression [field]
52 -S : sum the values instead of printing them
55 raise ArgumentError("No arguments passed")
56 pagesize
= kern
.globals.page_size
57 mangle
= 1 << (8 * kern
.ptrsize
- 1)
58 sbv
= pagesize
.GetSBValue()
59 v
= sbv
.CreateValueFromExpression(None, cmd_args
[0])
62 for i
in range(0, kern
.globals.zpercpu_early_count
):
63 if len(cmd_args
) == 1:
64 t
= sbv
.CreateValueFromExpression(None, '(%s)%d' % (v
.GetTypeName(), (int(e
) | mangle
) + i
* pagesize
)).Dereference()
66 t
= sbv
.CreateValueFromExpression(None, '((%s)%d)->%s' % (v
.GetTypeName(), (int(e
) | mangle
) + i
* pagesize
, cmd_args
[1]))
67 if "-S" in cmd_options
:
72 if "-S" in cmd_options
:
76 """ Formats the name for a given zone
78 zone - value : A pointer to a zone
80 the formated name for the zone
82 names
= [ "", "default.", "data.", "kext."]
83 return "{:s}{:s}".format(names
[int(zone
.kalloc_heap
)], zone
.z_name
)
85 def PrettyPrintDictionary(d
):
86 """ Internal function to pretty print a dictionary with string or integer values
87 params: The dictionary to print
89 for key
, value
in d
.items():
91 if isinstance(value
, int):
92 print "{:<30s} {: >10d}".format(key
, value
)
94 print "{:<30s} {: >10s}".format(key
, value
)
97 @lldb_command('memstats', 'J')
98 def Memstats(cmd_args
=None, cmd_options
={}):
99 """ 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.
104 if "-J" in cmd_options
:
109 memstats
["memorystatus_level"] = int(kern
.globals.memorystatus_level
)
110 memstats
["memorystatus_available_pages"] = int(kern
.globals.memorystatus_available_pages
)
111 memstats
["inuse_ptepages_count"] = int(kern
.globals.inuse_ptepages_count
)
114 if hasattr(kern
.globals, 'compressor_object'):
115 memstats
["compressor_page_count"] = int(kern
.globals.compressor_object
.resident_page_count
)
116 memstats
["vm_page_throttled_count"] = int(kern
.globals.vm_page_throttled_count
)
117 memstats
["vm_page_active_count"] = int(kern
.globals.vm_page_active_count
)
118 memstats
["vm_page_inactive_count"] = int(kern
.globals.vm_page_inactive_count
)
119 memstats
["vm_page_wire_count"] = int(kern
.globals.vm_page_wire_count
)
120 memstats
["vm_page_free_count"] = int(kern
.globals.vm_page_free_count
)
121 memstats
["vm_page_purgeable_count"] = int(kern
.globals.vm_page_purgeable_count
)
122 memstats
["vm_page_inactive_target"] = int(kern
.globals.vm_page_inactive_target
)
123 memstats
["vm_page_free_target"] = int(kern
.globals.vm_page_free_target
)
124 memstats
["vm_page_free_reserved"] = int(kern
.globals.vm_page_free_reserved
)
127 print json
.dumps(memstats
)
129 PrettyPrintDictionary(memstats
)
131 @xnudebug_test('test_memstats')
132 def TestMemstats(kernel_target
, config
, lldb_obj
, isConnected
):
133 """ Test the functionality of memstats command
139 print "Target is not connected. Cannot test memstats"
141 res
= lldb
.SBCommandReturnObject()
142 lldb_obj
.debugger
.GetCommandInterpreter().HandleCommand("memstats", res
)
143 result
= res
.GetOutput()
144 if result
.split(":")[1].strip().find('None') == -1 :
151 # Macro: showmemorystatus
152 def CalculateLedgerPeak(phys_footprint_entry
):
153 """ Internal function to calculate ledger peak value for the given phys footprint entry
154 params: phys_footprint_entry - value representing struct ledger_entry *
155 return: value - representing the ledger peak for the given phys footprint entry
157 now
= kern
.globals.sched_tick
/ 20
158 ledger_peak
= long(phys_footprint_entry
.le_credit
) - long(phys_footprint_entry
.le_debit
)
159 if hasattr(phys_footprint_entry
._le
._le
_max
, 'le_interval_max') and (long(phys_footprint_entry
._le
._le
_max
.le_interval_max
) > ledger_peak
):
160 ledger_peak
= long(phys_footprint_entry
._le
._le
_max
.le_interval_max
)
163 @header("{: >8s} {: >12s} {: >12s} {: >10s} {: >10s} {: >12s} {: >14s} {: >10s} {: >12s} {: >10s} {: >10s} {: >10s} {: <32s}\n".format(
164 'pid', 'effective', 'requested', 'state', 'relaunch', 'user_data', 'physical', 'iokit', 'footprint',
165 'recent peak', 'lifemax', 'limit', 'command'))
166 def GetMemoryStatusNode(proc_val
):
167 """ Internal function to get memorystatus information from the given proc
168 params: proc - value representing struct proc *
169 return: str - formatted output information for proc object
172 task_val
= Cast(proc_val
.task
, 'task *')
173 task_ledgerp
= task_val
.ledger
175 task_physmem_footprint_ledger_entry
= task_ledgerp
.l_entries
[kern
.globals.task_ledgers
.phys_mem
]
176 task_iokit_footprint_ledger_entry
= task_ledgerp
.l_entries
[kern
.globals.task_ledgers
.iokit_mapped
]
177 task_phys_footprint_ledger_entry
= task_ledgerp
.l_entries
[kern
.globals.task_ledgers
.phys_footprint
]
178 page_size
= kern
.globals.page_size
180 phys_mem_footprint
= (long(task_physmem_footprint_ledger_entry
.le_credit
) - long(task_physmem_footprint_ledger_entry
.le_debit
)) / page_size
181 iokit_footprint
= (long(task_iokit_footprint_ledger_entry
.le_credit
) - long(task_iokit_footprint_ledger_entry
.le_debit
)) / page_size
182 phys_footprint
= (long(task_phys_footprint_ledger_entry
.le_credit
) - long(task_phys_footprint_ledger_entry
.le_debit
)) / page_size
183 phys_footprint_limit
= long(task_phys_footprint_ledger_entry
.le_limit
) / page_size
184 ledger_peak
= CalculateLedgerPeak(task_phys_footprint_ledger_entry
)
185 phys_footprint_spike
= ledger_peak
/ page_size
186 phys_footprint_lifetime_max
= long(task_phys_footprint_ledger_entry
._le
._le
_max
.le_lifetime_max
) / page_size
188 format_string
= '{0: >8d} {1: >12d} {2: >12d} {3: #011x} {4: >10d} {5: #011x} {6: >12d} {7: >10d} {8: >13d}'
189 out_str
+= format_string
.format(proc_val
.p_pid
, proc_val
.p_memstat_effectivepriority
,
190 proc_val
.p_memstat_requestedpriority
, proc_val
.p_memstat_state
, proc_val
.p_memstat_relaunch_flags
,
191 proc_val
.p_memstat_userdata
, phys_mem_footprint
, iokit_footprint
, phys_footprint
)
192 if phys_footprint
!= phys_footprint_spike
:
193 out_str
+= "{: >12d}".format(phys_footprint_spike
)
195 out_str
+= "{: >12s}".format('-')
197 out_str
+= "{: >10d} ".format(phys_footprint_lifetime_max
)
198 out_str
+= "{: >10d} {: <32s}\n".format(phys_footprint_limit
, GetProcName(proc_val
))
201 @lldb_command('showmemorystatus')
202 def ShowMemoryStatus(cmd_args
=None):
203 """ Routine to display each entry in jetsam list with a summary of pressure statistics
204 Usage: showmemorystatus
208 print GetMemoryStatusNode
.header
209 print "{: >21s} {: >12s} {: >38s} {: >10s} {: >12s} {: >10s} {: >10s}\n".format("priority", "priority", "(pages)", "(pages)", "(pages)",
210 "(pages)", "(pages)", "(pages)")
211 while bucket_index
< bucket_count
:
212 current_bucket
= kern
.globals.memstat_bucket
[bucket_index
]
213 current_list
= current_bucket
.list
214 current_proc
= Cast(current_list
.tqh_first
, 'proc *')
215 while unsigned(current_proc
) != 0:
216 print GetMemoryStatusNode(current_proc
)
217 current_proc
= current_proc
.p_memstat_list
.tqe_next
222 # EndMacro: showmemorystatus
224 class ZoneMeta(object):
226 Helper class that helpers walking metadata
230 def _looksForeign(cls
, addr
):
231 if addr
& (kern
.globals.page_size
- 1):
234 meta
= kern
.GetValueFromAddress(addr
, "struct zone_page_metadata *")
235 return meta
.zm_foreign_cookie
[0] == 0x123456789abcdef
239 def __init__(self
, addr
, isPageIndex
= False):
241 pagesize
= kern
.globals.page_size
242 zone_info
= kern
.GetGlobalVariable('zone_info')
244 self
.zone_map_min
= unsigned(zone_info
.zi_map_range
.min_address
)
245 self
.zone_map_max
= unsigned(zone_info
.zi_map_range
.max_address
)
246 self
.zone_meta_min
= unsigned(zone_info
.zi_meta_range
.min_address
)
247 self
.zone_meta_max
= unsigned(zone_info
.zi_meta_range
.max_address
)
249 addr
= unsigned(addr
)
252 addr
= value(pagesize
.GetSBValue().CreateValueFromExpression(None,
253 '(long)(int)%d * %d' %(addr
, pagesize
)))
254 addr
= unsigned(addr
)
258 if self
.zone_meta_min
<= addr
and addr
< self
.zone_meta_max
:
259 self
.kind
= 'Metadata'
260 addr
-= (addr
- self
.zone_meta_min
) % sizeof('struct zone_page_metadata')
261 self
.meta_addr
= addr
262 self
.meta
= kern
.GetValueFromAddress(addr
, "struct zone_page_metadata *")
264 self
.page_addr
= self
.zone_map_min
+ ((addr
- self
.zone_meta_min
) / sizeof('struct zone_page_metadata') * pagesize
)
265 self
.first_offset
= 0
266 elif self
.zone_map_min
<= addr
and addr
< self
.zone_map_max
:
267 addr
&= ~
(pagesize
- 1)
268 page_idx
= (addr
- self
.zone_map_min
) / pagesize
270 self
.kind
= 'Element'
271 self
.page_addr
= addr
272 self
.meta_addr
= self
.zone_meta_min
+ page_idx
* sizeof('struct zone_page_metadata')
273 self
.meta
= kern
.GetValueFromAddress(self
.meta_addr
, "struct zone_page_metadata *")
274 self
.first_offset
= 0
275 elif ZoneMeta
._looksForeign
(addr
):
276 self
.kind
= 'Element (F)'
277 addr
&= ~
(pagesize
- 1)
278 self
.page_addr
= addr
279 self
.meta_addr
= addr
280 self
.meta
= kern
.GetValueFromAddress(addr
, "struct zone_page_metadata *")
281 self
.first_offset
= 32 # ZONE_FOREIGN_PAGE_FIRST_OFFSET in zalloc.c
283 self
.kind
= 'Unknown'
287 self
.first_offset
= 0
289 def isSecondaryPage(self
):
290 return self
.meta
and self
.meta
.zm_secondary_page
292 def getPageCount(self
):
293 return self
.meta
and self
.meta
.zm_page_count
or 0
295 def getAllocCount(self
):
296 return self
.meta
and self
.meta
.zm_alloc_count
or 0
299 if self
.isSecondaryPage():
300 return ZoneMeta(self
.meta
- self
.meta
.zm_page_count
)
304 def getFreeList(self
):
305 if self
.meta
and self
.meta
.zm_freelist_offs
!= unsigned(0xffff):
306 return kern
.GetValueFromAddress(self
.page_addr
+ self
.meta
.zm_freelist_offs
, 'vm_offset_t *')
309 def iterateFreeList(self
):
310 cur
= self
.getFreeList()
314 cur
= dereference(cast(cur
, 'vm_offset_t *'))
315 cur
= unsigned(cur
) ^
unsigned(kern
.globals.zp_nopoison_cookie
)
316 cur
= kern
.GetValueFromAddress(cur
, 'vm_offset_t *')
318 def iterateElements(self
):
319 if self
.meta
is None:
321 esize
= self
.getZone().z_elem_size
322 offs
= self
.first_offset
323 end
= kern
.globals.page_size
324 if not self
.meta
.zm_percpu
:
325 end
*= self
.meta
.zm_page_count
327 while offs
+ esize
<= end
:
328 yield kern
.GetValueFromAddress(self
.page_addr
+ offs
, 'void *')
333 return kern
.globals.zone_array
[self
.meta
.zm_index
]
336 @lldb_type_summary(['zone_page_metadata'])
337 @header("{:<18s} {:<18s} {:>8s} {:>8s} {:<18s} {:<20s}".format('ZONE_METADATA', 'FREELIST', 'PG_CNT', 'ALLOC_CNT', 'ZONE', 'NAME'))
338 def GetZoneMetadataSummary(meta
):
339 """ Summarize a zone metadata object
340 params: meta - obj representing zone metadata in the kernel
341 returns: str - summary of the zone metadata
344 if type(meta
) != ZoneMeta
:
345 meta
= ZoneMeta(meta
)
347 out_str
= 'Metadata Description:\n' + GetZoneMetadataSummary
.header
+ '\n'
348 if meta
.isSecondaryPage():
349 out_str
+= "{:#018x} {:#018x} {:8d} {:8d} {:#018x} {:s}\n".format(
350 meta
.meta_addr
, 0, 0, 0, 0, '(fake multipage meta)')
351 meta
= meta
.getReal()
352 zinfo
= meta
.getZone()
353 out_str
+= "{:#018x} {:#018x} {:8d} {:8d} {:#018x} {:s}".format(
354 meta
.meta_addr
, meta
.getFreeList(), meta
.getPageCount(), meta
.getAllocCount(),
355 addressof(zinfo
), ZoneName(zinfo
))
358 @header("{:<18s} {:>10s} {:>18s} {:>18s} {:<10s}".format(
359 'ADDRESS', 'TYPE', 'METADATA', 'PAGE_ADDR', 'OFFSET'))
361 """ Information about kernel pointer
365 meta
= ZoneMeta(addr
)
367 if meta
.meta
is None:
368 out_str
= "Address {:#018x} is outside of any zone map ({:#018x}-{:#018x})\n".format(
369 addr
, meta
.zone_map_min
, meta
.zone_map_max
)
371 if meta
.kind
[0] == 'E': # element
372 page_offset_str
= "{:d}/{:d}K".format(
373 addr
- meta
.page_addr
, kern
.globals.page_size
/ 1024)
375 page_offset_str
= "-"
376 out_str
= WhatIs
.header
+ '\n'
377 out_str
+= "{meta.address:#018x} {meta.kind:>10s} {meta.meta_addr:#018x} {meta.page_addr:#018x} {:<10s}\n\n".format(
378 page_offset_str
, meta
=meta
)
379 out_str
+= GetZoneMetadataSummary(meta
) + '\n\n'
383 if meta
.kind
[0] == 'E':
386 meta
= meta
.getReal()
387 esize
= meta
.getZone().z_elem_size
388 start
= meta
.page_addr
390 estart
= addr
- (start
- meta
.first_offset
)
391 estart
= start
+ estart
- (estart
% esize
)
395 data_array
= kern
.GetValueFromAddress(estart
- 16, "uint8_t *")
396 print_hex_data(data_array
[0:16], estart
- 16, "")
397 print "------------------------------------------------------------------"
402 data_array
= kern
.GetValueFromAddress(estart
, "uint8_t *")
403 print_hex_data(data_array
[0:esize
], estart
, "")
408 print "------------------------------------------------------------------"
409 data_array
= kern
.GetValueFromAddress(estart
+ esize
, "uint8_t *")
410 print_hex_data(data_array
[0:16], estart
+ esize
, "")
414 @lldb_command('whatis')
415 def WhatIsHelper(cmd_args
=None):
416 """ Routine to show information about a kernel pointer
417 Usage: whatis <address>
420 raise ArgumentError("No arguments passed")
421 WhatIs(kern
.GetValueFromAddress(cmd_args
[0], 'void *'))
425 @lldb_type_summary(['zone','zone_t'])
426 @header("{:<18s} {:>5s} {:>10s} {:>12s} {:>12s} {:>9s} {:>9s} {:>9s} {:>9s} {:>9s} {:<20s}".format(
427 'ZONE', 'ELTS', 'D FULL/EMPTY', 'ALLOCS', 'FREES', 'D_SWAP', 'D_FILL', 'D_DRAIN', 'D_GC', 'D_FAIL', 'NAME'))
429 def GetZoneCacheSummary(zone
, O
):
430 """ Summarize a zone's cache with important information.
432 zone: value - obj representing a zone in kernel
434 str - summary of the zone's cache contents
436 format_string
= '{:#018x} {:>5d} {:>4d} / {:>4d} {:>12,d} {:>12,d} {:>9,d} {:>9,d} {:>9,d} {:>9,d} {:>9,d} {:<20s}'
437 mag_capacity
= kern
.GetGlobalVariable('magazine_element_count')
438 depot_capacity
= kern
.GetGlobalVariable('depot_element_count')
444 if zone
.__getattr
__('cpu_cache_enabled') :
445 for cache
in IterateZPerCPU(zone
.zcache
.zcc_pcpu
, 'struct zcc_per_cpu_cache *'):
446 cache_elem_count
+= cache
.current
.zcc_magazine_index
447 cache_elem_count
+= cache
.previous
.zcc_magazine_index
448 allocs
+= cache
.zcc_allocs
449 frees
+= cache
.zcc_frees
451 depot
= zone
.zcache
.zcc_depot
452 cache_elem_count
+= depot
.zcc_depot_index
* mag_capacity
453 print O
.format(format_string
, zone
, cache_elem_count
,
454 depot
.zcc_depot_index
, depot_capacity
- depot
.zcc_depot_index
,
455 allocs
, frees
, depot
.zcc_swap
, depot
.zcc_fill
, depot
.zcc_drain
,
456 depot
.zcc_gc
, depot
.zcc_fail
, ZoneName(zone
))
458 @lldb_command('showzcache', fancy
=True)
459 def ZcachePrint(cmd_args
=None, cmd_options
={}, O
=None):
460 """ Routine to print a summary listing of all the kernel zones cache contents
461 All columns are printed in decimal
464 with O
.table(GetZoneCacheSummary
.header
):
465 for zval
in kern
.zones
:
466 if zval
.__getattr
__('cpu_cache_enabled') :
467 GetZoneCacheSummary(zval
, O
)
469 # EndMacro: showzcache
471 # Macro: showzcachecpu
473 @lldb_type_summary(['zone','zone_t'])
474 @header("{:18s} {:32s} {:<10s} {:<10s}".format(
475 'ZONE', 'NAME', 'CACHE_ELTS', 'CPU_INFO'))
477 def GetZoneCacheCPUSummary(zone
, O
):
478 """ Summarize a zone's cache broken up per cpu
480 zone: value - obj representing a zone in kernel
482 str - summary of the zone's per CPU cache contents
484 format_string
= '{:#018x} {:32s} {:10d} {cpuinfo:s}'
488 mag_capacity
= kern
.GetGlobalVariable('magazine_element_count')
489 depot_capacity
= kern
.GetGlobalVariable('depot_element_count')
491 if zone
.__getattr
__('cpu_cache_enabled') :
493 for cache
in IterateZPerCPU(zone
.zcache
.zcc_pcpu
, 'struct zcc_per_cpu_cache *'):
496 per_cpu_count
= cache
.current
.zcc_magazine_index
497 per_cpu_count
+= cache
.previous
.zcc_magazine_index
498 cache_elem_count
+= per_cpu_count
499 cpu_info
+= "CPU {:d}: {:5}".format(i
,per_cpu_count
)
501 cache_elem_count
+= zone
.zcache
.zcc_depot
.zcc_depot_index
* mag_capacity
503 print O
.format(format_string
, zone
, ZoneName(zone
), cache_elem_count
,cpuinfo
= cpu_info
)
505 @lldb_command('showzcachecpu', fancy
=True)
506 def ZcacheCPUPrint(cmd_args
=None, cmd_options
={}, O
=None):
507 """ Routine to print a summary listing of all the kernel zones cache contents
508 All columns are printed in decimal
511 with O
.table(GetZoneCacheCPUSummary
.header
):
512 for zval
in kern
.zones
:
513 if zval
.__getattr
__('cpu_cache_enabled'):
514 GetZoneCacheCPUSummary(zval
, O
)
516 # EndMacro: showzcachecpu
520 def GetZone(zone_val
, marks
):
521 """ Internal function which gets a phython dictionary containing important zone information.
523 zone_val: value - obj representing a zone in kernel
525 zone - python dictionary with zone stats
527 pagesize
= kern
.globals.page_size
529 zone
["free_size"] = zone_val
.countfree
* zone_val
.pcpu_elem_size
530 mag_capacity
= kern
.GetGlobalVariable('magazine_element_count')
531 zone
["page_count"] = unsigned(zone_val
.page_count
)
532 zone
["allfree_page_count"] = unsigned(zone_val
.allfree_page_count
)
534 zone
["size"] = zone_val
.page_count
* pagesize
535 zone
["used_size"] = zone
["size"] - zone
["free_size"]
536 zone
["element_count"] = zone_val
.countavail
- zone_val
.countfree
539 zone
["allocation_size"] = unsigned(pagesize
)
540 zone
["allocation_ncpu"] = unsigned(zone_val
.alloc_pages
)
542 zone
["allocation_size"] = unsigned(zone_val
.alloc_pages
* pagesize
)
543 zone
["allocation_ncpu"] = 1
544 zone
["allocation_count"] = zone
["allocation_size"] / zone_val
.z_elem_size
545 zone
["allocation_waste"] = (zone
["allocation_size"] % zone_val
.z_elem_size
) * zone
["allocation_ncpu"]
547 if not zone_val
.__getattr
__("z_self") :
548 zone
["destroyed"] = True
550 zone
["destroyed"] = False
553 if zone_val
.__getattr
__(mark
[0]):
556 zone
[mark
[0]] = False
559 if zone_val
.__getattr
__('cpu_cache_enabled') :
560 for cache
in IterateZPerCPU(zone_val
.zcache
.zcc_pcpu
, 'struct zcc_per_cpu_cache *'):
561 cache_elem_count
+= cache
.current
.zcc_magazine_index
562 cache_elem_count
+= cache
.previous
.zcc_magazine_index
563 cache_elem_count
+= zone_val
.zcache
.zcc_depot
.zcc_depot_index
* mag_capacity
564 zone
["cache_element_count"] = cache_elem_count
565 zone
["name"] = ZoneName(zone_val
)
566 if zone_val
.exhaustible
:
567 zone
["exhaustible"] = True
569 zone
["exhaustible"] = False
571 zone
["sequester_page_count"] = unsigned(zone_val
.sequester_page_count
)
572 zone
["page_count_max"] = unsigned(zone_val
.page_count_max
)
577 @lldb_type_summary(['zone','zone_t'])
578 @header(("{:<18s} {:_^35s} {:_^24s} {:_^13s} {:_^28s}\n"+
579 "{:<18s} {:>11s} {:>11s} {:>11s} {:>8s} {:>7s} {:>7s} {:>6s} {:>6s} {:>8s} {:>6s} {:>5s} {:>7s} {:<18s} {:<20s}").format(
580 '', 'SIZE (bytes)', 'ELEMENTS (#)', 'PAGES', 'ALLOC CHUNK CONFIG',
581 'ZONE', 'TOTAL', 'ALLOC', 'FREE', 'ALLOC', 'FREE', 'CACHE', 'COUNT', 'FREE', 'SIZE (P)', 'ELTS', 'WASTE', 'ELT_SZ', 'FLAGS', 'NAME'))
582 def GetZoneSummary(zone_val
, marks
, stats
):
583 """ Summarize a zone with important information. See help zprint for description of each field
585 zone_val: value - obj representing a zone in kernel
587 str - summary of the zone
589 pagesize
= kern
.globals.page_size
591 zone
= GetZone(zone_val
, marks
)
593 format_string
= '{zone:#018x} {cur_size:11,d} {used_size:11,d} {free_size:11,d} '
594 format_string
+= '{count_elts:8,d} {zone.countfree:7,d} {cache_elem_count:7,d} '
595 format_string
+= '{zone.page_count:6,d} {zone.allfree_page_count:6,d} '
596 format_string
+= '{alloc_size_kb:3,d}K ({zone.alloc_pages:d}) {alloc_count:6,d} {alloc_waste:5,d} {zone.pcpu_elem_size:7,d} '
597 format_string
+= '{markings:<18s} {zone_name:<20s}'
600 if zone
["destroyed"]:
609 alloc_size_kb
= zone
["allocation_size"] / 1024
610 out_string
+= format_string
.format(zone
=zone_val
, free_size
=zone
["free_size"], used_size
=zone
["used_size"],
611 cur_size
=zone
["size"], count_elts
=zone
["element_count"], cache_elem_count
=zone
["cache_element_count"],
612 alloc_count
=zone
["allocation_count"], alloc_size_kb
=alloc_size_kb
, alloc_waste
=zone
["allocation_waste"],
613 markings
=markings
, zone_name
=zone
["name"])
615 if zone
["exhaustible"] :
616 out_string
+= " (max: {:d})".format(zone
["page_count_max"] * pagesize
)
618 if zone
["sequester_page_count"] != 0 :
619 out_string
+= " (sequester: {:d})".format(zone
["sequester_page_count"])
621 stats
["cur_size"] += zone
["size"]
622 stats
["used_size"] += zone
["used_size"]
623 stats
["free_size"] += zone
["free_size"]
624 stats
["cur_pages"] += zone
["page_count"]
625 stats
["free_pages"] += zone
["allfree_page_count"]
626 stats
["seq_pages"] += zone
["sequester_page_count"]
630 @lldb_command('zprint', "J", fancy
=True)
631 def Zprint(cmd_args
=None, cmd_options
={}, O
=None):
632 """ Routine to print a summary listing of all the kernel zones
635 All columns are printed in decimal
640 $ - not encrypted during hibernation
642 F - allows foreign memory (memory not allocated from any zone map)
643 M - gzalloc will avoid monitoring this zone
644 R - will be refilled when below low water mark
645 O - does not allow refill callout to fill zone on noblock allocation
646 N - zone requires alignment (avoids padding this zone for debugging)
647 A - currently trying to allocate more backing memory from kernel_memory_allocate without VM priv
648 S - currently trying to allocate more backing memory from kernel_memory_allocate with VM priv
649 W - another thread is waiting for more memory
650 E - Per-cpu caching is enabled for this zone
651 L - zone is being monitored by zleaks
652 G - currently running GC
653 I - zone was destroyed and is no longer valid
658 ["collectable", "C"],
659 ["destructible", "D"],
662 ["exhaustible", "H"],
663 ["allows_foreign", "F"],
664 ["prio_refill_count", "R"],
667 ["expanding_no_vm_priv", "A"],
668 ["expanding_vm_priv", "S"],
670 ["cpu_cache_enabled", "E"],
671 ["gzalloc_exempt", "M"],
672 ["alignment_required", "N"],
673 ["va_sequester", "!"]
676 "cur_size": 0, "used_size": 0, "free_size": 0,
677 "cur_pages": 0, "free_pages": 0, "seq_pages": 0
681 if "-J" in cmd_options
:
686 for zval
in kern
.zones
:
688 zones
.append(GetZone(zval
, marks
))
690 print json
.dumps(zones
)
692 with O
.table(GetZoneSummary
.header
):
693 for zval
in kern
.zones
:
695 print GetZoneSummary(zval
, marks
, stats
)
697 format_string
= '{VT.Bold}{name:19s} {stats[cur_size]:11,d} {stats[used_size]:11,d} {stats[free_size]:11,d} '
699 format_string
+= '{stats[cur_pages]:6,d} {stats[free_pages]:6,d}{VT.EndBold} '
700 format_string
+= '(sequester: {VT.Bold}{stats[seq_pages]:,d}{VT.EndBold})'
701 print O
.format(format_string
, name
="TOTALS", filler
="", stats
=stats
)
704 @xnudebug_test('test_zprint')
705 def TestZprint(kernel_target
, config
, lldb_obj
, isConnected
):
706 """ Test the functionality of zprint command
712 print "Target is not connected. Cannot test memstats"
714 res
= lldb
.SBCommandReturnObject()
715 lldb_obj
.debugger
.GetCommandInterpreter().HandleCommand("zprint", res
)
716 result
= res
.GetOutput()
717 if len(result
.split("\n")) > 2:
725 # Macro: showzfreelist
727 def ShowZfreeListHeader(zone
):
728 """ Helper routine to print a header for zone freelist.
729 (Since the freelist does not have a custom type, this is not defined as a Type Summary).
731 zone:zone_t - Zone object to print header info
736 scaled_factor
= (unsigned(kern
.globals.zp_factor
) +
737 (unsigned(zone
.z_elem_size
) >> unsigned(kern
.globals.zp_scale
)))
740 out_str
+= "{0: <9s} {1: <12s} {2: <18s} {3: <18s} {4: <6s}\n".format('ELEM_SIZE', 'COUNT', 'NCOOKIE', 'PCOOKIE', 'FACTOR')
741 out_str
+= "{0: <9d} {1: <12d} 0x{2:0>16x} 0x{3:0>16x} {4: <2d}/{5: <2d}\n\n".format(
742 zone
.z_elem_size
, zone
.countavail
- zone
.countfree
, kern
.globals.zp_nopoison_cookie
, kern
.globals.zp_poisoned_cookie
, zone
.zp_count
, scaled_factor
)
743 out_str
+= "{0: <7s} {1: <18s} {2: <18s} {3: <18s} {4: <18s} {5: <18s} {6: <14s}\n".format(
744 'NUM', 'ELEM', 'NEXT', 'BACKUP', '^ NCOOKIE', '^ PCOOKIE', 'POISON (PREV)')
747 def ShowZfreeListChain(zone
, zfirst
, zlimit
):
748 """ Helper routine to print a zone free list chain
750 zone: zone_t - Zone object
751 zfirst: void * - A pointer to the first element of the free list chain
752 zlimit: int - Limit for the number of elements to be printed by showzfreelist
756 current
= Cast(zfirst
, 'void *')
757 while ShowZfreeList
.elts_found
< zlimit
:
758 ShowZfreeList
.elts_found
+= 1
759 znext
= dereference(Cast(current
, 'vm_offset_t *'))
760 znext
= (unsigned(znext
) ^
unsigned(kern
.globals.zp_nopoison_cookie
))
761 znext
= kern
.GetValueFromAddress(znext
, 'vm_offset_t *')
762 backup_ptr
= kern
.GetValueFromAddress((unsigned(Cast(current
, 'vm_offset_t')) + unsigned(zone
.z_elem_size
) - sizeof('vm_offset_t')), 'vm_offset_t *')
763 backup_val
= dereference(backup_ptr
)
764 n_unobfuscated
= (unsigned(backup_val
) ^
unsigned(kern
.globals.zp_nopoison_cookie
))
765 p_unobfuscated
= (unsigned(backup_val
) ^
unsigned(kern
.globals.zp_poisoned_cookie
))
767 if p_unobfuscated
== unsigned(znext
):
768 poison_str
= "P ({0: <d})".format(ShowZfreeList
.elts_found
- ShowZfreeList
.last_poisoned
)
769 ShowZfreeList
.last_poisoned
= ShowZfreeList
.elts_found
771 if n_unobfuscated
!= unsigned(znext
):
772 poison_str
= "INVALID"
773 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(
774 ShowZfreeList
.elts_found
, unsigned(current
), unsigned(znext
),
775 unsigned(backup_val
), n_unobfuscated
, p_unobfuscated
, poison_str
)
776 if unsigned(znext
) == 0:
778 current
= Cast(znext
, 'void *')
780 def ZoneIteratePageQueue(page
):
781 while page
.packed_address
:
782 meta
= ZoneMeta(page
.packed_address
, isPageIndex
=True)
784 page
= meta
.meta
.zm_page_next
786 @static_var('elts_found',0)
787 @static_var('last_poisoned',0)
788 @lldb_command('showzfreelist')
789 def ShowZfreeList(cmd_args
=None):
790 """ Walk the freelist for a zone, printing out the primary and backup next pointers, the poisoning cookies, and the poisoning status of each element.
791 Usage: showzfreelist <zone> [iterations]
793 Will walk up to 50 elements by default, pass a limit in 'iterations' to override.
796 print ShowZfreeList
.__doc
__
798 ShowZfreeList
.elts_found
= 0
799 ShowZfreeList
.last_poisoned
= 0
801 zone
= kern
.GetValueFromAddress(cmd_args
[0], 'struct zone *')
803 if len(cmd_args
) >= 2:
804 zlimit
= ArgumentStringToInt(cmd_args
[1])
805 ShowZfreeListHeader(zone
)
807 for head
in [zone
.pages_any_free_foreign
, zone
.pages_intermediate
, zone
.pages_all_free
]:
808 for free_page_meta
in ZoneIteratePageQueue(head
):
809 if ShowZfreeList
.elts_found
== zlimit
:
811 zfirst
= free_page_meta
.getFreeList()
813 ShowZfreeListChain(zone
, zfirst
, zlimit
)
815 if ShowZfreeList
.elts_found
== zlimit
:
816 print "Stopped at {0: <d} elements!".format(zlimit
)
818 print "Found {0: <d} elements!".format(ShowZfreeList
.elts_found
)
820 # EndMacro: showzfreelist
822 # Macro: zstack_showzonesbeinglogged
824 @lldb_command('zstack_showzonesbeinglogged')
825 def ZstackShowZonesBeingLogged(cmd_args
=None):
826 """ Show all zones which have BTLog enabled.
829 for zval
in kern
.zones
:
831 print "Zone: %s with its BTLog at: 0x%lx" % (ZoneName(zval
), zval
.zlog_btlog
)
833 # EndMacro: zstack_showzonesbeinglogged
837 @lldb_command('zstack')
838 def Zstack(cmd_args
=None):
839 """ Zone leak debugging: Print the stack trace logged at <index> in the stacks list. If a <count> is supplied, it prints <count> stacks starting at <index>.
840 Usage: zstack <btlog addr> <index> [<count>]
842 The suggested usage is to look at stacks with high percentage of refs (maybe > 25%).
843 The stack trace that occurs the most is probably the cause of the leak. Use zstack_findleak for that.
848 if int(kern
.globals.log_records
) == 0:
849 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
852 btlog_ptr
= kern
.GetValueFromAddress(cmd_args
[0], 'btlog_t *')
853 btrecords_total_size
= unsigned(btlog_ptr
.btlog_buffersize
)
854 btrecord_size
= unsigned(btlog_ptr
.btrecord_size
)
855 btrecords
= unsigned(btlog_ptr
.btrecords
)
856 btlog_size
= unsigned(sizeof('struct btlog'))
857 depth
= unsigned(btlog_ptr
.btrecord_btdepth
)
858 zstack_index
= ArgumentStringToInt(cmd_args
[1])
860 if len(cmd_args
) >= 3:
861 count
= ArgumentStringToInt(cmd_args
[2])
863 max_count
= ((btrecords_total_size
- btlog_size
)/btrecord_size
)
865 if (zstack_index
+ count
) > max_count
:
866 count
= max_count
- zstack_index
868 while count
and (zstack_index
!= 0xffffff):
869 zstack_record_offset
= zstack_index
* btrecord_size
870 zstack_record
= kern
.GetValueFromAddress(btrecords
+ zstack_record_offset
, 'btlog_record_t *')
871 if int(zstack_record
.ref_count
)!=0:
872 ShowZStackRecord(zstack_record
, zstack_index
, depth
, unsigned(btlog_ptr
.active_element_count
))
878 # Macro: zstack_inorder
880 @lldb_command('zstack_inorder')
881 def ZstackInOrder(cmd_args
=None):
882 """ Zone leak debugging: Print the stack traces starting from head to the tail.
883 Usage: zstack_inorder <btlog addr>
886 print "Zone leak debugging: Print the stack traces starting from head to the tail. \nUsage: zstack_inorder <btlog addr>"
888 if int(kern
.globals.log_records
) == 0:
889 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
892 btlog_ptr
= kern
.GetValueFromAddress(cmd_args
[0], 'btlog_t *')
893 btrecords_total_size
= unsigned(btlog_ptr
.btlog_buffersize
)
894 btrecord_size
= unsigned(btlog_ptr
.btrecord_size
)
895 btrecords
= unsigned(btlog_ptr
.btrecords
)
896 btlog_size
= unsigned(sizeof('struct btlog'))
897 depth
= unsigned(btlog_ptr
.btrecord_btdepth
)
898 zstack_head
= unsigned(btlog_ptr
.head
)
899 zstack_index
= zstack_head
900 zstack_tail
= unsigned(btlog_ptr
.tail
)
901 count
= ((btrecords_total_size
- btlog_size
)/btrecord_size
)
903 while count
and (zstack_index
!= 0xffffff):
904 zstack_record_offset
= zstack_index
* btrecord_size
905 zstack_record
= kern
.GetValueFromAddress(btrecords
+ zstack_record_offset
, 'btlog_record_t *')
906 ShowZStackRecord(zstack_record
, zstack_index
, depth
, unsigned(btlog_ptr
.active_element_count
))
907 zstack_index
= zstack_record
.next
910 # EndMacro : zstack_inorder
914 @lldb_command('findoldest')
915 def FindOldest(cmd_args
=None):
918 print "***** DEPRECATED ***** use 'zstack_findleak' macro instead."
920 # EndMacro : findoldest
922 # Macro : zstack_findleak
924 @lldb_command('zstack_findleak')
925 def zstack_findleak(cmd_args
=None):
926 """ Zone leak debugging: search the log and print the stack with the most active references
928 Usage: zstack_findleak <btlog address>
930 This is useful for verifying a suspected stack as being the source of
933 btlog_ptr
= kern
.GetValueFromAddress(cmd_args
[0], 'btlog_t *')
934 btrecord_size
= unsigned(btlog_ptr
.btrecord_size
)
935 btrecords
= unsigned(btlog_ptr
.btrecords
)
937 cpcs_index
= unsigned(btlog_ptr
.head
)
938 depth
= unsigned(btlog_ptr
.btrecord_btdepth
)
943 while cpcs_index
!= 0xffffff:
944 cpcs_record_offset
= cpcs_index
* btrecord_size
945 cpcs_record
= kern
.GetValueFromAddress(btrecords
+ cpcs_record_offset
, 'btlog_record_t *')
946 if cpcs_record
.ref_count
> highref
:
947 highref_record
= cpcs_record
948 highref
= cpcs_record
.ref_count
949 highref_index
= cpcs_index
950 cpcs_index
= cpcs_record
.next
951 ShowZStackRecord(highref_record
, highref_index
, depth
, unsigned(btlog_ptr
.active_element_count
))
953 # EndMacro: zstack_findleak
957 @lldb_command('findelem')
958 def FindElem(cmd_args
=None):
961 print "***** DEPRECATED ***** use 'zstack_findelem' macro instead."
965 @lldb_command('zstack_findelem')
966 def ZStackFindElem(cmd_args
=None):
967 """ Zone corruption debugging: search the zone log and print out the stack traces for all log entries that
968 refer to the given zone element.
969 Usage: zstack_findelem <btlog addr> <elem addr>
971 When the kernel panics due to a corrupted zone element, get the
972 element address and use this command. This will show you the stack traces of all logged zalloc and
973 zfree operations which tells you who touched the element in the recent past. This also makes
974 double-frees readily apparent.
977 print ZStackFindElem
.__doc
__
979 if int(kern
.globals.log_records
) == 0 or unsigned(kern
.globals.corruption_debug_flag
) == 0:
980 print "Zone logging with corruption detection not enabled. Add '-zc zlog=<zone name>' to boot-args."
983 btlog_ptr
= kern
.GetValueFromAddress(cmd_args
[0], 'btlog_t *')
984 target_element
= unsigned(kern
.GetValueFromAddress(cmd_args
[1], 'void *'))
986 btrecord_size
= unsigned(btlog_ptr
.btrecord_size
)
987 btrecords
= unsigned(btlog_ptr
.btrecords
)
988 depth
= unsigned(btlog_ptr
.btrecord_btdepth
)
992 hashelem
= cast(btlog_ptr
.elem_linkage_un
.element_hash_queue
.tqh_first
, 'btlog_element_t *')
993 if (target_element
>> 32) != 0:
994 target_element
= target_element ^
0xFFFFFFFFFFFFFFFF
996 target_element
= target_element ^
0xFFFFFFFF
998 if unsigned(hashelem
.elem
) == target_element
:
999 recindex
= hashelem
.recindex
1000 recoffset
= recindex
* btrecord_size
1001 record
= kern
.GetValueFromAddress(btrecords
+ recoffset
, 'btlog_record_t *')
1003 if record
.operation
== 1:
1004 out_str
+= "OP: ALLOC. "
1006 out_str
+= "OP: FREE. "
1007 out_str
+= "Stack Index {0: <d} {1: <s}\n".format(recindex
, ('-' * 8))
1009 print GetBtlogBacktrace(depth
, record
)
1011 if int(record
.operation
) == prev_op
:
1012 print "{0: <s} DOUBLE OP! {1: <s}".format(('*' * 8), ('*' * 8))
1014 prev_op
= int(record
.operation
)
1016 hashelem
= cast(hashelem
.element_hash_link
.tqe_next
, 'btlog_element_t *')
1018 if scan_items
% 100 == 0:
1019 print "Scanning is ongoing. {0: <d} items scanned since last check." .format(scan_items
)
1021 # EndMacro: zstack_findelem
1023 @lldb_command('zstack_findtop', 'N:')
1024 def ShowZstackTop(cmd_args
=None, cmd_options
={}):
1025 """ Zone leak debugging: search the log and print the stacks with the most active references
1028 Usage: zstack_findtop [-N <n-stacks>] <btlog-addr>
1032 raise ArgumentError('Missing required btlog address argument')
1035 if '-N' in cmd_options
:
1036 n
= int(cmd_options
['-N'])
1038 btlog_ptr
= kern
.GetValueFromAddress(cmd_args
[0], 'btlog_t *')
1039 btrecord_size
= unsigned(btlog_ptr
.btrecord_size
)
1040 btrecords
= unsigned(btlog_ptr
.btrecords
)
1042 cpcs_index
= unsigned(btlog_ptr
.head
)
1043 depth
= unsigned(btlog_ptr
.btrecord_btdepth
)
1046 while cpcs_index
!= 0xffffff:
1047 cpcs_record_offset
= cpcs_index
* btrecord_size
1048 cpcs_record
= kern
.GetValueFromAddress(btrecords
+ cpcs_record_offset
, 'btlog_record_t *')
1049 cpcs_record
.index
= cpcs_index
1050 records
.append(cpcs_record
)
1051 cpcs_index
= cpcs_record
.next
1053 recs
= sorted(records
, key
=lambda x
: x
.ref_count
, reverse
=True)
1055 for rec
in recs
[:n
]:
1056 ShowZStackRecord(rec
, rec
.index
, depth
, unsigned(btlog_ptr
.active_element_count
))
1058 # EndMacro: zstack_findtop
1062 @lldb_command('btlog_find', "AS")
1063 def BtlogFind(cmd_args
=None, cmd_options
={}):
1066 print "***** DEPRECATED ***** use 'zstack_findelem' macro instead."
1069 #EndMacro: btlog_find
1073 @lldb_command('showzalloc')
1074 def ShowZalloc(cmd_args
=None):
1075 """ Prints a zallocation from the zallocations array based off its index and prints the associated symbolicated backtrace.
1076 Usage: showzalloc <index>
1079 print ShowZalloc
.__doc
__
1081 if unsigned(kern
.globals.zallocations
) == 0:
1082 print "zallocations array not initialized!"
1084 zallocation
= kern
.globals.zallocations
[ArgumentStringToInt(cmd_args
[0])]
1086 ShowZTrace([str(int(zallocation
.za_trace_index
))])
1088 #EndMacro: showzalloc
1092 @lldb_command('showztrace')
1093 def ShowZTrace(cmd_args
=None):
1094 """ Prints the backtrace from the ztraces array at index
1095 Usage: showztrace <trace index>
1098 print ShowZTrace
.__doc
__
1100 if unsigned(kern
.globals.ztraces
) == 0:
1101 print "ztraces array not initialized!"
1103 ztrace_addr
= kern
.globals.ztraces
[ArgumentStringToInt(cmd_args
[0])]
1105 ShowZstackTraceHelper(ztrace_addr
.zt_stack
, ztrace_addr
.zt_depth
)
1107 #EndMacro: showztrace
1109 #Macro: showztraceaddr
1111 @lldb_command('showztraceaddr')
1112 def ShowZTraceAddr(cmd_args
=None):
1113 """ Prints the struct ztrace passed in.
1114 Usage: showztraceaddr <trace address>
1117 print ShowZTraceAddr
.__doc
__
1119 ztrace_ptr
= kern
.GetValueFromAddress(cmd_args
[0], 'struct ztrace *')
1120 print dereference(ztrace_ptr
)
1121 ShowZstackTraceHelper(ztrace_ptr
.zt_stack
, ztrace_ptr
.zt_depth
)
1123 #EndMacro: showztraceaddr
1125 #Macro: showzstacktrace
1127 @lldb_command('showzstacktrace')
1128 def ShowZstackTrace(cmd_args
=None):
1129 """ Routine to print a stacktrace stored by OSBacktrace.
1130 Usage: showzstacktrace <saved stacktrace> [size]
1132 size is optional, defaults to 15.
1135 print ShowZstackTrace
.__doc
__
1137 void_ptr_type
= gettype('void *')
1138 void_double_ptr_type
= void_ptr_type
.GetPointerType()
1139 trace
= kern
.GetValueFromAddress(cmd_args
[0], void_double_ptr_type
)
1141 if len(cmd_args
) >= 2:
1142 trace_size
= ArgumentStringToInt(cmd_args
[1])
1143 ShowZstackTraceHelper(trace
, trace_size
)
1145 #EndMacro: showzstacktrace
1147 def ShowZstackTraceHelper(stack
, depth
):
1148 """ Helper routine for printing a zstack.
1150 stack: void *[] - An array of pointers representing the Zstack
1151 depth: int - The depth of the ztrace stack
1156 while trace_current
< depth
:
1157 trace_addr
= stack
[trace_current
]
1158 symbol_arr
= kern
.SymbolicateFromAddress(unsigned(trace_addr
))
1160 symbol_str
= str(symbol_arr
[0].addr
)
1163 print '{0: <#x} {1: <s}'.format(trace_addr
, symbol_str
)
1166 #Macro: showtopztrace
1168 @lldb_command('showtopztrace')
1169 def ShowTopZtrace(cmd_args
=None):
1170 """ Shows the ztrace with the biggest size.
1171 (According to top_ztrace, not by iterating through the hash table)
1173 top_trace
= kern
.globals.top_ztrace
1174 print 'Index: {0: <d}'.format((unsigned(top_trace
) - unsigned(kern
.globals.ztraces
)) / sizeof('struct ztrace'))
1175 print dereference(top_trace
)
1176 ShowZstackTraceHelper(top_trace
.zt_stack
, top_trace
.zt_depth
)
1178 #EndMacro: showtopztrace
1182 @lldb_command('showzallocs')
1183 def ShowZallocs(cmd_args
=None):
1184 """ Prints all allocations in the zallocations table
1186 if unsigned(kern
.globals.zallocations
) == 0:
1187 print "zallocations array not initialized!"
1189 print '{0: <5s} {1: <18s} {2: <5s} {3: <15s}'.format('INDEX','ADDRESS','TRACE','SIZE')
1191 max_zallocation
= unsigned(kern
.globals.zleak_alloc_buckets
)
1192 allocation_count
= 0
1193 while current_index
< max_zallocation
:
1194 current_zalloc
= kern
.globals.zallocations
[current_index
]
1195 if int(current_zalloc
.za_element
) != 0:
1196 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
))
1197 allocation_count
+= 1
1199 print 'Total Allocations: {0: <d}'.format(allocation_count
)
1201 #EndMacro: showzallocs
1203 #Macro: showzallocsfortrace
1205 @lldb_command('showzallocsfortrace')
1206 def ShowZallocsForTrace(cmd_args
=None):
1207 """ Prints all allocations pointing to the passed in trace's index into ztraces by looking through zallocations table
1208 Usage: showzallocsfortrace <trace index>
1211 print ShowZallocsForTrace
.__doc
__
1213 print '{0: <5s} {1: <18s} {2: <15s}'.format('INDEX','ADDRESS','SIZE')
1214 target_index
= ArgumentStringToInt(cmd_args
[0])
1216 max_zallocation
= unsigned(kern
.globals.zleak_alloc_buckets
)
1217 allocation_count
= 0
1218 while current_index
< max_zallocation
:
1219 current_zalloc
= kern
.globals.zallocations
[current_index
]
1220 if unsigned(current_zalloc
.za_element
) != 0 and (unsigned(current_zalloc
.za_trace_index
) == unsigned(target_index
)):
1221 print '{0: <5d} {1: <#018x} {2: <6d}'.format(current_index
, current_zalloc
.za_element
, current_zalloc
.za_size
)
1222 allocation_count
+= 1
1224 print 'Total Allocations: {0: <d}'.format(allocation_count
)
1226 #EndMacro: showzallocsfortrace
1230 @lldb_command('showztraces')
1231 def ShowZTraces(cmd_args
=None):
1232 """ Prints all traces with size > 0
1234 ShowZTracesAbove([0])
1236 #EndMacro: showztraces
1238 #Macro: showztracesabove
1240 @lldb_command('showztracesabove')
1241 def ShowZTracesAbove(cmd_args
=None):
1242 """ Prints all traces with size greater than X
1243 Usage: showztracesabove <size>
1246 print ShowZTracesAbove
.__doc
__
1248 print '{0: <5s} {1: <6s}'.format('INDEX','SIZE')
1251 max_ztrace
= unsigned(kern
.globals.zleak_trace_buckets
)
1252 while current_index
< max_ztrace
:
1253 ztrace_current
= kern
.globals.ztraces
[current_index
]
1254 if ztrace_current
.zt_size
> unsigned(cmd_args
[0]):
1255 print '{0: <5d} {1: <6d}'.format(current_index
, int(ztrace_current
.zt_size
))
1258 print 'Total traces: {0: <d}'.format(ztrace_count
)
1260 #EndMacro: showztracesabove
1262 #Macro: showztracehistogram
1264 @lldb_command('showztracehistogram')
1265 def ShowZtraceHistogram(cmd_args
=None):
1266 """ Prints the histogram of the ztrace table
1268 print '{0: <5s} {1: <9s} {2: <10s}'.format('INDEX','HIT_COUNT','COLLISIONS')
1271 max_ztrace
= unsigned(kern
.globals.zleak_trace_buckets
)
1272 while current_index
< max_ztrace
:
1273 ztrace_current
= kern
.globals.ztraces
[current_index
]
1274 if ztrace_current
.zt_hit_count
!= 0:
1275 print '{0: <5d} {1: <9d} {2: <10d}'.format(current_index
, ztrace_current
.zt_hit_count
, ztrace_current
.zt_collisions
)
1278 print 'Total traces: {0: <d}'.format(ztrace_count
)
1280 #EndMacro: showztracehistogram
1282 #Macro: showzallochistogram
1284 @lldb_command('showzallochistogram')
1285 def ShowZallocHistogram(cmd_args
=None):
1286 """ Prints the histogram for the zalloc table
1288 print '{0: <5s} {1: <9s}'.format('INDEX','HIT_COUNT')
1290 zallocation_count
= 0
1291 max_ztrace
= unsigned(kern
.globals.zleak_alloc_buckets
)
1292 while current_index
< max_ztrace
:
1293 zallocation_current
= kern
.globals.zallocations
[current_index
]
1294 if zallocation_current
.za_hit_count
!= 0:
1295 print '{0: <5d} {1: <9d}'.format(current_index
, zallocation_current
.za_hit_count
)
1296 zallocation_count
+= 1
1298 print 'Total Allocations: {0: <d}'.format(zallocation_count
)
1300 #EndMacro: showzallochistogram
1304 @lldb_command('showzstats')
1305 def ShowZstats(cmd_args
=None):
1306 """ Prints the zone leak detection stats
1308 print 'z_alloc_collisions: {0: <d}, z_trace_collisions: {1: <d}'.format(unsigned(kern
.globals.z_alloc_collisions
), unsigned(kern
.globals.z_trace_collisions
))
1309 print 'z_alloc_overwrites: {0: <d}, z_trace_overwrites: {1: <d}'.format(unsigned(kern
.globals.z_alloc_overwrites
), unsigned(kern
.globals.z_trace_overwrites
))
1310 print 'z_alloc_recorded: {0: <d}, z_trace_recorded: {1: <d}'.format(unsigned(kern
.globals.z_alloc_recorded
), unsigned(kern
.globals.z_trace_recorded
))
1312 #EndMacro: showzstats
1316 @lldb_command('showpcpu', "N:V", fancy
=True)
1317 def ShowPCPU(cmd_args
=None, cmd_options
={}, O
=None):
1318 """ Show per-cpu variables
1319 usage: showpcpu [-N <cpu>] [-V] <variable name>
1321 Use -N <cpu> to only dump the value for a given CPU number
1322 Use -V to dump the values of the variables after their addresses
1326 raise ArgumentError("No arguments passed")
1329 ncpu
= kern
.globals.zpercpu_early_count
1330 pcpu_base
= kern
.globals.percpu_base
1332 if "-N" in cmd_options
:
1333 cpu
= unsigned(int(cmd_options
["-N"]))
1334 if cpu
>= unsigned(ncpu
):
1335 raise ArgumentError("Invalid cpu {d}".format(cpu
))
1337 var
= addressof(kern
.GetGlobalVariable('percpu_slot_' + cmd_args
[0]))
1338 ty
= var
.GetSBValue().GetTypeName()
1342 r
= range(cpu
, cpu
+ 1)
1344 def PCPUSlot(pcpu_var
, i
):
1347 addr
= unsigned(pcpu_var
) + unsigned(pcpu_base
.start
) + (i
- 1) * unsigned(pcpu_base
.size
)
1348 return kern
.GetValueFromAddress(addr
, pcpu_var
)
1350 with O
.table("{:<4s} {:<20s}".format("CPU", "address")):
1352 print O
.format("{:<4d} ({:s}){:#x}", i
, ty
, PCPUSlot(var
, i
))
1354 if not "-V" in cmd_options
:
1358 with O
.table("CPU {:d}".format(i
)):
1359 print dereference(PCPUSlot(var
, i
))
1363 def GetBtlogBacktrace(depth
, zstack_record
):
1364 """ Helper routine for getting a BT Log record backtrace stack.
1366 depth:int - The depth of the zstack record
1367 zstack_record:btlog_record_t * - A BTLog record
1369 str - string with backtrace in it.
1373 if not zstack_record
:
1374 return "Zstack record none!"
1376 depth_val
= unsigned(depth
)
1377 while frame
< depth_val
:
1378 frame_pc
= zstack_record
.bt
[frame
]
1379 if not frame_pc
or int(frame_pc
) == 0:
1381 symbol_arr
= kern
.SymbolicateFromAddress(frame_pc
)
1383 symbol_str
= str(symbol_arr
[0].addr
)
1386 out_str
+= "{0: <#0x} <{1: <s}>\n".format(frame_pc
, symbol_str
)
1390 def ShowZStackRecord(zstack_record
, zstack_index
, btrecord_btdepth
, elements_count
):
1391 """ Helper routine for printing a single zstack record
1393 zstack_record:btlog_record_t * - A BTLog record
1394 zstack_index:int - Index for the record in the BTLog table
1399 if zstack_record
.operation
== 1:
1400 out_str
+= "ALLOC. "
1403 out_str
+= "Stack Index {0: <d} with active refs {1: <d} of {2: <d} {3: <s}\n".format(zstack_index
, zstack_record
.ref_count
, elements_count
, ('-' * 8))
1405 print GetBtlogBacktrace(btrecord_btdepth
, zstack_record
)
1408 # Macro: showioalloc
1410 @lldb_command('showioalloc')
1411 def ShowIOAllocations(cmd_args
=None):
1412 """ Show some accounting of memory allocated by IOKit allocators. See ioalloccount man page for details.
1413 Routine to display a summary of memory accounting allocated by IOKit allocators.
1415 print "Instance allocation = {0: <#0x} = {1: d}K".format(kern
.globals.debug_ivars_size
, (kern
.globals.debug_ivars_size
/ 1024))
1416 print "Container allocation = {0: <#0x} = {1: d}K".format(kern
.globals.debug_container_malloc_size
, (kern
.globals.debug_container_malloc_size
/ 1024))
1417 print "IOMalloc allocation = {0: <#0x} = {1: d}K".format(kern
.globals.debug_iomalloc_size
, (kern
.globals.debug_iomalloc_size
/ 1024))
1418 print "Container allocation = {0: <#0x} = {1: d}K".format(kern
.globals.debug_iomallocpageable_size
, (kern
.globals.debug_iomallocpageable_size
/ 1024))
1421 # EndMacro: showioalloc
1424 # Macro: showselectmem
1425 @lldb_command('showselectmem', "S:")
1426 def ShowSelectMem(cmd_args
=None, cmd_options
={}):
1427 """ Show memory cached by threads on calls to select.
1429 usage: showselectmem [-v]
1430 -v : print each thread's memory
1431 (one line per thread with non-zero select memory)
1432 -S {addr} : Find the thread whose thread-local select set
1433 matches the given address
1437 if config
['verbosity'] > vHUMAN
:
1439 if "-S" in cmd_options
:
1440 opt_wqs
= unsigned(kern
.GetValueFromAddress(cmd_options
["-S"], 'uint64_t *'))
1442 raise ArgumentError("Invalid waitq set address: {:s}".format(cmd_options
["-S"]))
1445 print "{:18s} {:10s} {:s}".format('Task', 'Thread ID', 'Select Mem (bytes)')
1446 for t
in kern
.tasks
:
1447 for th
in IterateQueue(t
.threads
, 'thread *', 'task_threads'):
1448 uth
= Cast(th
.uthread
, 'uthread *');
1450 if hasattr(uth
, 'uu_allocsize'): # old style
1451 thmem
= uth
.uu_allocsize
1453 elif hasattr(uth
, 'uu_wqstate_sz'): # new style
1454 thmem
= uth
.uu_wqstate_sz
1457 print "What kind of uthread is this?!"
1459 if opt_wqs
and opt_wqs
== unsigned(wqs
):
1460 print "FOUND: {:#x} in thread: {:#x} ({:#x})".format(opt_wqs
, unsigned(th
), unsigned(th
.thread_id
))
1461 if verbose
and thmem
> 0:
1462 print "{:<#18x} {:<#10x} {:d}".format(unsigned(t
), unsigned(th
.thread_id
), thmem
)
1465 print "Total: {:d} bytes ({:d} kbytes)".format(selmem
, selmem
/1024)
1466 # Endmacro: showselectmem
1469 # Macro: showtaskvme
1470 @lldb_command('showtaskvme', "PS")
1471 def ShowTaskVmeHelper(cmd_args
=None, cmd_options
={}):
1472 """ Display a summary list of the specified vm_map's entries
1473 Usage: showtaskvme <task address> (ex. showtaskvme 0x00ataskptr00 )
1474 Use -S flag to show VM object shadow chains
1475 Use -P flag to show pager info (mapped file, compressed pages, ...)
1477 show_pager_info
= False
1478 show_all_shadows
= False
1479 if "-P" in cmd_options
:
1480 show_pager_info
= True
1481 if "-S" in cmd_options
:
1482 show_all_shadows
= True
1483 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
1484 ShowTaskVMEntries(task
, show_pager_info
, show_all_shadows
)
1486 @lldb_command('showallvme', "PS")
1487 def ShowAllVME(cmd_args
=None, cmd_options
={}):
1488 """ Routine to print a summary listing of all the vm map entries
1489 Go Through each task in system and show the vm memory regions
1490 Use -S flag to show VM object shadow chains
1491 Use -P flag to show pager info (mapped file, compressed pages, ...)
1493 show_pager_info
= False
1494 show_all_shadows
= False
1495 if "-P" in cmd_options
:
1496 show_pager_info
= True
1497 if "-S" in cmd_options
:
1498 show_all_shadows
= True
1499 for task
in kern
.tasks
:
1500 ShowTaskVMEntries(task
, show_pager_info
, show_all_shadows
)
1502 @lldb_command('showallvm')
1503 def ShowAllVM(cmd_args
=None):
1504 """ Routine to print a summary listing of all the vm maps
1506 for task
in kern
.tasks
:
1507 print GetTaskSummary
.header
+ ' ' + GetProcSummary
.header
1508 print GetTaskSummary(task
) + ' ' + GetProcSummary(Cast(task
.bsd_info
, 'proc *'))
1509 print GetVMMapSummary
.header
1510 print GetVMMapSummary(task
.map)
1512 @lldb_command("showtaskvm")
1513 def ShowTaskVM(cmd_args
=None):
1514 """ Display info about the specified task's vm_map
1515 syntax: (lldb) showtaskvm <task_ptr>
1518 print ShowTaskVM
.__doc
__
1520 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
1522 print "Unknown arguments."
1524 print GetTaskSummary
.header
+ ' ' + GetProcSummary
.header
1525 print GetTaskSummary(task
) + ' ' + GetProcSummary(Cast(task
.bsd_info
, 'proc *'))
1526 print GetVMMapSummary
.header
1527 print GetVMMapSummary(task
.map)
1530 @lldb_command('showallvmstats')
1531 def ShowAllVMStats(cmd_args
=None):
1532 """ Print a summary of vm statistics in a table format
1534 page_size
= kern
.globals.page_size
1535 vmstats
= lambda:None
1536 vmstats
.wired_count
= 0
1537 vmstats
.resident_count
= 0
1538 vmstats
.resident_max
= 0
1539 vmstats
.internal
= 0
1540 vmstats
.external
= 0
1541 vmstats
.reusable
= 0
1542 vmstats
.compressed
= 0
1543 vmstats
.compressed_peak
= 0
1544 vmstats
.compressed_lifetime
= 0
1547 hdr_format
= "{:>6s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:<20s} {:1s}"
1548 print hdr_format
.format('#ents', 'wired', 'vsize', 'rsize', 'NEW RSIZE', 'max rsize', 'internal', 'external', 'reusable', 'compressed', 'compressed', 'compressed', 'pid', 'command', '')
1549 print hdr_format
.format('', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(current)', '(peak)', '(lifetime)', '', '', '')
1550 entry_format
= "{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} {p.p_pid: >10d} {0: <32s} {s.error}"
1552 for task
in kern
.tasks
:
1553 proc
= Cast(task
.bsd_info
, 'proc *')
1554 vmmap
= Cast(task
.map, '_vm_map *')
1556 vmstats
.wired_count
= vmmap
.pmap
.stats
.wired_count
;
1557 vmstats
.resident_count
= unsigned(vmmap
.pmap
.stats
.resident_count
);
1558 vmstats
.resident_max
= vmmap
.pmap
.stats
.resident_max
;
1559 vmstats
.internal
= unsigned(vmmap
.pmap
.stats
.internal
);
1560 vmstats
.external
= unsigned(vmmap
.pmap
.stats
.external
);
1561 vmstats
.reusable
= unsigned(vmmap
.pmap
.stats
.reusable
);
1562 vmstats
.compressed
= unsigned(vmmap
.pmap
.stats
.compressed
);
1563 vmstats
.compressed_peak
= unsigned(vmmap
.pmap
.stats
.compressed_peak
);
1564 vmstats
.compressed_lifetime
= unsigned(vmmap
.pmap
.stats
.compressed_lifetime
);
1565 vmstats
.new_resident_count
= vmstats
.internal
+ vmstats
.external
1567 if vmstats
.internal
< 0:
1568 vmstats
.error
+= '*'
1569 if vmstats
.external
< 0:
1570 vmstats
.error
+= '*'
1571 if vmstats
.reusable
< 0:
1572 vmstats
.error
+= '*'
1573 if vmstats
.compressed
< 0:
1574 vmstats
.error
+= '*'
1575 if vmstats
.compressed_peak
< 0:
1576 vmstats
.error
+= '*'
1577 if vmstats
.compressed_lifetime
< 0:
1578 vmstats
.error
+= '*'
1579 if vmstats
.new_resident_count
+vmstats
.reusable
!= vmstats
.resident_count
:
1580 vmstats
.error
+= '*'
1582 print entry_format
.format(GetProcName(proc
), p
=proc
, m
=vmmap
, vsize
=(unsigned(vmmap
.size
) / page_size
), t
=task
, s
=vmstats
)
1585 def ShowTaskVMEntries(task
, show_pager_info
, show_all_shadows
):
1586 """ Routine to print out a summary listing of all the entries in a vm_map
1588 task - core.value : a object of type 'task *'
1592 print "vm_map entries for task " + hex(task
)
1593 print GetTaskSummary
.header
1594 print GetTaskSummary(task
)
1596 print "Task {0: <#020x} has map = 0x0"
1598 print GetVMMapSummary
.header
1599 print GetVMMapSummary(task
.map)
1600 vme_list_head
= task
.map.hdr
.links
1601 vme_ptr_type
= GetType('vm_map_entry *')
1602 print GetVMEntrySummary
.header
1603 for vme
in IterateQueue(vme_list_head
, vme_ptr_type
, "links"):
1604 print GetVMEntrySummary(vme
, show_pager_info
, show_all_shadows
)
1607 @lldb_command("showmap")
1608 def ShowMap(cmd_args
=None):
1609 """ Routine to print out info about the specified vm_map
1610 usage: showmap <vm_map>
1612 if cmd_args
== None or len(cmd_args
) < 1:
1613 print "Invalid argument.", ShowMap
.__doc
__
1615 map_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vm_map_t')
1616 print GetVMMapSummary
.header
1617 print GetVMMapSummary(map_val
)
1619 @lldb_command("showmapvme")
1620 def ShowMapVME(cmd_args
=None):
1621 """Routine to print out info about the specified vm_map and its vm entries
1622 usage: showmapvme <vm_map>
1624 if cmd_args
== None or len(cmd_args
) < 1:
1625 print "Invalid argument.", ShowMapVME
.__doc
__
1627 map_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vm_map_t')
1628 print GetVMMapSummary
.header
1629 print GetVMMapSummary(map_val
)
1630 vme_list_head
= map_val
.hdr
.links
1631 vme_ptr_type
= GetType('vm_map_entry *')
1632 print GetVMEntrySummary
.header
1633 for vme
in IterateQueue(vme_list_head
, vme_ptr_type
, "links"):
1634 print GetVMEntrySummary(vme
)
1637 @lldb_type_summary(['_vm_map *', 'vm_map_t'])
1638 @header("{0: <20s} {1: <20s} {2: <20s} {3: >5s} {4: >5s} {5: <20s} {6: <20s} {7: <7s}".format("vm_map", "pmap", "vm_size", "#ents", "rpage", "hint", "first_free", "pgshift"))
1639 def GetVMMapSummary(vmmap
):
1640 """ Display interesting bits from vm_map struct """
1642 format_string
= "{0: <#020x} {1: <#020x} {2: <#020x} {3: >5d} {4: >5d} {5: <#020x} {6: <#020x} {7: >7d}"
1643 vm_size
= uint64_t(vmmap
.size
).value
1645 if vmmap
.pmap
!= 0: resident_pages
= int(vmmap
.pmap
.stats
.resident_count
)
1647 if int(vmmap
.holelistenabled
) == 0: first_free
= vmmap
.f_s
._first
_free
1648 out_string
+= format_string
.format(vmmap
, vmmap
.pmap
, vm_size
, vmmap
.hdr
.nentries
, resident_pages
, vmmap
.hint
, first_free
, vmmap
.hdr
.page_shift
)
1651 @lldb_type_summary(['vm_map_entry'])
1652 @header("{0: <20s} {1: <20s} {2: <5s} {3: >7s} {4: <20s} {5: <20s}".format("entry", "start", "prot", "#page", "object", "offset"))
1653 def GetVMEntrySummary(vme
):
1654 """ Display vm entry specific information. """
1655 page_size
= kern
.globals.page_size
1657 format_string
= "{0: <#020x} {1: <#20x} {2: <1x}{3: <1x}{4: <3s} {5: >7d} {6: <#020x} {7: <#020x}"
1658 vme_protection
= int(vme
.protection
)
1659 vme_max_protection
= int(vme
.max_protection
)
1660 vme_extra_info_str
="SC-Ds"[int(vme
.inheritance
)]
1661 if int(vme
.is_sub_map
) != 0 :
1662 vme_extra_info_str
+="s"
1663 elif int(vme
.needs_copy
) != 0 :
1664 vme_extra_info_str
+="n"
1665 num_pages
= (unsigned(vme
.links
.end
) - unsigned(vme
.links
.start
)) / page_size
1666 out_string
+= format_string
.format(vme
, vme
.links
.start
, vme_protection
, vme_max_protection
, vme_extra_info_str
, num_pages
, vme
.vme_object
.vmo_object
, vme
.vme_offset
)
1669 # EndMacro: showtaskvme
1670 @lldb_command('showmapwired')
1671 def ShowMapWired(cmd_args
=None):
1672 """ Routine to print out a summary listing of all the entries with wired pages in a vm_map
1674 if cmd_args
== None or len(cmd_args
) < 1:
1675 print "Invalid argument", ShowMapWired
.__doc
__
1677 map_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vm_map_t')
1680 @lldb_type_summary(['kmod_info_t *'])
1681 @header("{0: <20s} {1: <20s} {2: <20s} {3: >3s} {4: >5s} {5: <20s} {6: <20s} {7: >20s} {8: <30s}".format('kmod_info', 'address', 'size', 'id', 'refs', 'TEXT exec', 'size', 'version', 'name'))
1682 def GetKextSummary(kmod
):
1683 """ returns a string representation of kext information
1686 format_string
= "{0: <#020x} {1: <#020x} {2: <#020x} {3: >3d} {4: >5d} {5: <#020x} {6: <#020x} {7: >20s} {8: <30s}"
1687 segments
, sections
= GetAllSegmentsAndSectionsFromDataInMemory(unsigned(kmod
.address
), unsigned(kmod
.size
))
1688 text_segment
= macho
.get_text_segment(segments
)
1689 if not text_segment
:
1690 text_segment
= segments
[0]
1691 out_string
+= format_string
.format(kmod
, kmod
.address
, kmod
.size
, kmod
.id, kmod
.reference_count
, text_segment
.vmaddr
, text_segment
.vmsize
, kmod
.version
, kmod
.name
)
1694 @lldb_type_summary(['uuid_t'])
1696 def GetUUIDSummary(uuid
):
1697 """ returns a string representation like CA50DA4C-CA10-3246-B8DC-93542489AA26
1699 arr
= Cast(addressof(uuid
), 'uint8_t *')
1702 data
.append(int(arr
[i
]))
1703 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
)
1705 @lldb_command('showallkmods')
1706 def ShowAllKexts(cmd_args
=None):
1707 """Display a summary listing of all loaded kexts (alias: showallkmods)
1709 kmod_val
= kern
.globals.kmod
1710 kextuuidinfo
= GetKextLoadInformation(show_progress
=(config
['verbosity'] > vHUMAN
))
1711 print "{: <36s} ".format("UUID") + GetKextSummary
.header
1712 for kval
in IterateLinkedList(kmod_val
, 'next'):
1713 uuid
= "........-....-....-....-............"
1714 kaddr
= unsigned(kval
.address
)
1715 found_kext_summary
= None
1716 for l
in kextuuidinfo
:
1717 if kaddr
== int(l
[3],16):
1719 found_kext_summary
= l
1721 if found_kext_summary
:
1722 _ksummary
= GetKextSummary(found_kext_summary
[7])
1724 _ksummary
= GetKextSummary(kval
)
1725 print uuid
+ " " + _ksummary
1727 def GetKmodWithAddr(addr
):
1728 """ Go through kmod list and find one with begin_addr as addr
1729 returns: None if not found. else a cvalue of type kmod
1731 kmod_val
= kern
.globals.kmod
1732 for kval
in IterateLinkedList(kmod_val
, 'next'):
1733 if addr
== unsigned(kval
.address
):
1737 def GetAllSegmentsAndSectionsFromDataInMemory(address
, size
):
1738 """ reads memory at address and parses mach_header to get segment and section information
1739 returns: Tuple of (segments_list, sections_list) like ([MachOSegment,...], [MachOSegment, ...])
1740 where MachOSegment has fields like 'name vmaddr vmsize fileoff filesize'
1741 if TEXT segment is not found a dummy segment & section with address, size is returned.
1743 cache_hash
= "kern.kexts.segments.{}.{}".format(address
, size
)
1744 cached_result
= caching
.GetDynamicCacheData(cache_hash
,())
1746 return cached_result
1748 defval
= macho
.MachOSegment('__TEXT', address
, size
, 0, size
)
1749 if address
== 0 or size
== 0:
1750 return ([defval
], [defval
])
1752 ## if int(kern.globals.gLoadedKextSummaries.version) <= 2:
1753 # until we have separate version. we will pay penalty only on arm64 devices
1754 if not kern
.arch
.startswith('arm64'):
1755 return ([defval
], [defval
])
1757 restrict_size_to_read
= 1536
1759 while machoObject
is None:
1760 err
= lldb
.SBError()
1761 size_to_read
= min(size
, restrict_size_to_read
)
1762 data
= LazyTarget
.GetProcess().ReadMemory(address
, size_to_read
, err
)
1763 if not err
.Success():
1764 print "Failed to read memory at {} and size {}".format(address
, size_to_read
)
1765 return ([defval
], [defval
])
1767 m
= macho
.MemMacho(data
, len(data
))
1769 except Exception as e
:
1770 if str(e
.message
).find('unpack requires a string argument') >= 0:
1771 # this may be due to short read of memory. Lets do double read size.
1772 restrict_size_to_read
*= 2
1773 debuglog("Bumping mach header read size to {}".format(restrict_size_to_read
))
1776 print "Failed to read MachO for address {} errormessage: {}".format(address
, e
.message
)
1777 return ([defval
], [defval
])
1778 # end of while loop. We have machoObject defined
1779 segments
= machoObject
.get_segments_with_name('')
1780 sections
= machoObject
.get_sections_with_name('')
1781 rval
= (segments
, sections
)
1782 caching
.SaveDynamicCacheData(cache_hash
, rval
)
1785 def GetKextLoadInformation(addr
=0, show_progress
=False):
1786 """ Extract the kext uuid and load address information from the kernel data structure.
1788 addr - int - optional integer that is the address to search for.
1790 [] - array with each entry of format
1791 ( 'UUID', 'Hex Load Address of __TEXT or __TEXT_EXEC section', 'name',
1792 'addr of macho header', [macho.MachOSegment,..], [MachoSection,...], kext, kmod_obj)
1794 cached_result
= caching
.GetDynamicCacheData("kern.kexts.loadinformation", [])
1795 ## if specific addr is provided then ignore caching
1796 if cached_result
and not addr
:
1797 return cached_result
1799 # because of <rdar://problem/12683084>, we can't find summaries directly
1800 #addr = hex(addressof(kern.globals.gLoadedKextSummaries.summaries))
1801 baseaddr
= unsigned(kern
.globals.gLoadedKextSummaries
) + 0x10
1802 summaries_begin
= kern
.GetValueFromAddress(baseaddr
, 'OSKextLoadedKextSummary *')
1803 total_summaries
= int(kern
.globals.gLoadedKextSummaries
.numSummaries
)
1804 kext_version
= int(kern
.globals.gLoadedKextSummaries
.version
)
1805 entry_size
= 64 + 16 + 8 + 8 + 8 + 4 + 4
1806 if kext_version
>= 2 :
1807 entry_size
= int(kern
.globals.gLoadedKextSummaries
.entry_size
)
1809 for i
in range(total_summaries
):
1811 print "progress: {}/{}".format(i
, total_summaries
)
1812 tmpaddress
= unsigned(summaries_begin
) + (i
* entry_size
)
1813 current_kext
= kern
.GetValueFromAddress(tmpaddress
, 'OSKextLoadedKextSummary *')
1814 # code to extract macho information
1815 segments
, sections
= GetAllSegmentsAndSectionsFromDataInMemory(unsigned(current_kext
.address
), unsigned(current_kext
.size
))
1816 seginfo
= macho
.get_text_segment(segments
)
1818 seginfo
= segments
[0]
1819 kmod_obj
= GetKmodWithAddr(unsigned(current_kext
.address
))
1821 if addr
== unsigned(current_kext
.address
) or addr
== seginfo
.vmaddr
:
1822 return [(GetUUIDSummary(current_kext
.uuid
) , hex(seginfo
.vmaddr
).rstrip('L'), str(current_kext
.name
), hex(current_kext
.address
), segments
, seginfo
, current_kext
, kmod_obj
)]
1823 retval
.append((GetUUIDSummary(current_kext
.uuid
) , hex(seginfo
.vmaddr
).rstrip('L'), str(current_kext
.name
), hex(current_kext
.address
), segments
, seginfo
, current_kext
, kmod_obj
))
1826 caching
.SaveDynamicCacheData("kern.kexts.loadinformation", retval
)
1829 lldb_alias('showallkexts', 'showallkmods')
1831 def GetOSKextVersion(version_num
):
1832 """ returns a string of format 1.2.3x from the version_num
1833 params: version_num - int
1836 if version_num
== -1 :
1838 (MAJ_MULT
, MIN_MULT
, REV_MULT
,STAGE_MULT
) = (100000000, 1000000, 10000, 1000)
1839 version
= version_num
1841 vers_major
= version
/ MAJ_MULT
1842 version
= version
- (vers_major
* MAJ_MULT
)
1844 vers_minor
= version
/ MIN_MULT
1845 version
= version
- (vers_minor
* MIN_MULT
)
1847 vers_revision
= version
/ REV_MULT
1848 version
= version
- (vers_revision
* REV_MULT
)
1850 vers_stage
= version
/ STAGE_MULT
1851 version
= version
- (vers_stage
* STAGE_MULT
)
1853 vers_stage_level
= version
1855 out_str
= "%d.%d" % (vers_major
, vers_minor
)
1856 if vers_revision
> 0: out_str
+= ".%d" % vers_revision
1857 if vers_stage
== 1 : out_str
+= "d%d" % vers_stage_level
1858 if vers_stage
== 3 : out_str
+= "a%d" % vers_stage_level
1859 if vers_stage
== 5 : out_str
+= "b%d" % vers_stage_level
1860 if vers_stage
== 6 : out_str
+= "fc%d" % vers_stage_level
1864 @lldb_command('showallknownkmods')
1865 def ShowAllKnownKexts(cmd_args
=None):
1866 """ Display a summary listing of all kexts known in the system.
1867 This is particularly useful to find if some kext was unloaded before this crash'ed state.
1869 kext_count
= int(kern
.globals.sKextsByID
.count
)
1871 kext_dictionary
= kern
.globals.sKextsByID
.dictionary
1872 print "%d kexts in sKextsByID:" % kext_count
1873 print "{0: <20s} {1: <20s} {2: >5s} {3: >20s} {4: <30s}".format('OSKEXT *', 'load_addr', 'id', 'version', 'name')
1874 format_string
= "{0: <#020x} {1: <20s} {2: >5s} {3: >20s} {4: <30s}"
1876 while index
< kext_count
:
1877 kext_dict
= GetObjectAtIndexFromArray(kext_dictionary
, index
)
1878 kext_name
= str(kext_dict
.key
.string
)
1879 osk
= Cast(kext_dict
.value
, 'OSKext *')
1880 if int(osk
.flags
.loaded
) :
1881 load_addr
= "{0: <#020x}".format(osk
.kmod_info
)
1882 id = "{0: >5d}".format(osk
.loadTag
)
1884 load_addr
= "------"
1886 version_num
= unsigned(osk
.version
)
1887 version
= GetOSKextVersion(version_num
)
1888 print format_string
.format(osk
, load_addr
, id, version
, kext_name
)
1893 def FindKmodNameForAddr(addr
):
1894 """ Given an address, return the name of the kext containing that address
1896 addr
= unsigned(addr
)
1897 all_kexts_info
= GetKextLoadInformation()
1898 for kinfo
in all_kexts_info
:
1899 segment
= macho
.get_segment_with_addr(kinfo
[4], addr
)
1901 return kinfo
[7].name
1905 @lldb_command('addkextaddr')
1906 def AddKextAddr(cmd_args
=[]):
1907 """ Given an address, load the kext which contains that address
1908 Syntax: (lldb) addkextaddr <addr>
1910 if len(cmd_args
) < 1:
1911 raise ArgumentError("Insufficient arguments")
1913 addr
= ArgumentStringToInt(cmd_args
[0])
1914 all_kexts_info
= GetKextLoadInformation()
1915 kernel_uuid
= str(kern
.globals.kernel_uuid_string
).lower()
1917 found_segment
= None
1918 for kinfo
in all_kexts_info
:
1919 segment
= macho
.get_segment_with_addr(kinfo
[4], addr
)
1921 print GetKextSummary
.header
1922 print GetKextSummary(kinfo
[7]) + " segment: {} offset = {:#0x}".format(segment
.name
, (addr
- segment
.vmaddr
))
1923 cur_uuid
= kinfo
[0].lower()
1924 if (kernel_uuid
== cur_uuid
):
1927 print "Fetching dSYM for %s" % cur_uuid
1928 info
= dsymForUUID(cur_uuid
)
1929 if info
and 'DBGSymbolRichExecutable' in info
:
1930 print "Adding dSYM (%s) for %s" % (cur_uuid
, info
['DBGSymbolRichExecutable'])
1931 addDSYM(cur_uuid
, info
)
1932 loadDSYM(cur_uuid
, int(kinfo
[1],16), kinfo
[4])
1934 print "Failed to get symbol info for %s" % cur_uuid
1938 @lldb_command('showkmodaddr')
1939 def ShowKmodAddr(cmd_args
=[]):
1940 """ Given an address, print the offset and name for the kmod containing it
1941 Syntax: (lldb) showkmodaddr <addr>
1943 if len(cmd_args
) < 1:
1944 raise ArgumentError("Insufficient arguments")
1946 addr
= ArgumentStringToInt(cmd_args
[0])
1947 all_kexts_info
= GetKextLoadInformation()
1949 found_segment
= None
1950 for kinfo
in all_kexts_info
:
1951 s
= macho
.get_segment_with_addr(kinfo
[4], addr
)
1957 print GetKextSummary
.header
1958 print GetKextSummary(found_kinfo
[7]) + " segment: {} offset = {:#0x}".format(found_segment
.name
, (addr
- found_segment
.vmaddr
))
1963 @lldb_command('addkext','AF:N:')
1964 def AddKextSyms(cmd_args
=[], cmd_options
={}):
1965 """ Add kext symbols into lldb.
1966 This command finds symbols for a uuid and load the required executable
1968 addkext <uuid> : Load one kext based on uuid. eg. (lldb)addkext 4DD2344C0-4A81-3EAB-BDCF-FEAFED9EB73E
1969 addkext -F <abs/path/to/executable> <load_address> : Load kext executable at specified load address
1970 addkext -N <name> : Load one kext that matches the name provided. eg. (lldb) addkext -N corecrypto
1971 addkext -N <name> -A: Load all kext that matches the name provided. eg. to load all kext with Apple in name do (lldb) addkext -N Apple -A
1972 addkext all : Will load all the kext symbols - SLOW
1976 if "-F" in cmd_options
:
1977 exec_path
= cmd_options
["-F"]
1978 exec_full_path
= ResolveFSPath(exec_path
)
1979 if not os
.path
.exists(exec_full_path
):
1980 raise ArgumentError("Unable to resolve {:s}".format(exec_path
))
1982 if not os
.path
.isfile(exec_full_path
):
1983 raise ArgumentError("Path is {:s} not a filepath. \nPlease check that path points to executable.\
1984 \nFor ex. path/to/Symbols/IOUSBFamily.kext/Contents/PlugIns/AppleUSBHub.kext/Contents/MacOS/AppleUSBHub.\
1985 \nNote: LLDB does not support adding kext based on directory paths like gdb used to.".format(exec_path
))
1990 slide_value
= cmd_args
[0]
1991 debuglog("loading slide value from user input %s" % cmd_args
[0])
1993 filespec
= lldb
.SBFileSpec(exec_full_path
, False)
1994 print "target modules add %s" % exec_full_path
1995 print lldb_run_command("target modules add %s" % exec_full_path
)
1996 loaded_module
= LazyTarget
.GetTarget().FindModule(filespec
)
1997 if loaded_module
.IsValid():
1998 uuid_str
= loaded_module
.GetUUIDString()
1999 debuglog("added module %s with uuid %s" % (exec_full_path
, uuid_str
))
2000 if slide_value
is None:
2001 all_kexts_info
= GetKextLoadInformation()
2002 for k
in all_kexts_info
:
2004 if k
[0].lower() == uuid_str
.lower():
2007 debuglog("found the slide %s for uuid %s" % (k
[1], k
[0]))
2008 if slide_value
is None:
2009 raise ArgumentError("Unable to find load address for module described at %s " % exec_full_path
)
2012 cmd_str
= "target modules load --file %s --slide %s" % ( exec_full_path
, str(slide_value
))
2015 cmd_str
= "target modules load --file {} ".format(exec_full_path
)
2018 sections_str
+= " {} {:#0x} ".format(s
.name
, s
.vmaddr
)
2019 cmd_str
+= sections_str
2022 lldb
.debugger
.HandleCommand(cmd_str
)
2024 kern
.symbolicator
= None
2027 all_kexts_info
= GetKextLoadInformation()
2028 kernel_uuid
= str(kern
.globals.kernel_uuid_string
).lower()
2030 if "-N" in cmd_options
:
2031 kext_name
= cmd_options
["-N"]
2032 kext_name_matches
= GetLongestMatchOption(kext_name
, [str(x
[2]) for x
in all_kexts_info
], True)
2033 if len(kext_name_matches
) != 1 and "-A" not in cmd_options
:
2034 print "Ambiguous match for name: {:s}".format(kext_name
)
2035 if len(kext_name_matches
) > 0:
2036 print "Options are:\n\t" + "\n\t".join(kext_name_matches
)
2038 debuglog("matched the kext to name %s and uuid %s" % (kext_name_matches
[0], kext_name
))
2039 for cur_knm
in kext_name_matches
:
2040 for x
in all_kexts_info
:
2042 cur_uuid
= x
[0].lower()
2043 if (kernel_uuid
== cur_uuid
):
2046 print "Fetching dSYM for {:s}".format(cur_uuid
)
2047 info
= dsymForUUID(cur_uuid
)
2048 if info
and 'DBGSymbolRichExecutable' in info
:
2049 print "Adding dSYM ({0:s}) for {1:s}".format(cur_uuid
, info
['DBGSymbolRichExecutable'])
2050 addDSYM(cur_uuid
, info
)
2051 loadDSYM(cur_uuid
, int(x
[1],16), x
[4])
2053 print "Failed to get symbol info for {:s}".format(cur_uuid
)
2055 kern
.symbolicator
= None
2058 if len(cmd_args
) < 1:
2059 raise ArgumentError("No arguments specified.")
2061 uuid
= cmd_args
[0].lower()
2063 load_all_kexts
= False
2065 load_all_kexts
= True
2067 if not load_all_kexts
and len(uuid_regex
.findall(uuid
)) == 0:
2068 raise ArgumentError("Unknown argument {:s}".format(uuid
))
2070 for k_info
in all_kexts_info
:
2071 cur_uuid
= k_info
[0].lower()
2072 if load_all_kexts
or (uuid
== cur_uuid
):
2073 if (kernel_uuid
!= cur_uuid
):
2074 print "Fetching dSYM for %s" % cur_uuid
2075 info
= dsymForUUID(cur_uuid
)
2076 if info
and 'DBGSymbolRichExecutable' in info
:
2077 print "Adding dSYM (%s) for %s" % (cur_uuid
, info
['DBGSymbolRichExecutable'])
2078 addDSYM(cur_uuid
, info
)
2079 loadDSYM(cur_uuid
, int(k_info
[1],16), k_info
[4])
2081 print "Failed to get symbol info for %s" % cur_uuid
2083 kern
.symbolicator
= None
2088 lldb_alias('showkmod', 'showkmodaddr')
2089 lldb_alias('showkext', 'showkmodaddr')
2090 lldb_alias('showkextaddr', 'showkmodaddr')
2092 @lldb_type_summary(['mount *'])
2093 @header("{0: <20s} {1: <20s} {2: <20s} {3: <12s} {4: <12s} {5: <12s} {6: >6s} {7: <30s} {8: <35s} {9: <30s}".format('volume(mp)', 'mnt_data', 'mnt_devvp', 'flag', 'kern_flag', 'lflag', 'type', 'mnton', 'mntfrom', 'iosched supported'))
2094 def GetMountSummary(mount
):
2095 """ Display a summary of mount on the system
2097 out_string
= ("{mnt: <#020x} {mnt.mnt_data: <#020x} {mnt.mnt_devvp: <#020x} {mnt.mnt_flag: <#012x} " +
2098 "{mnt.mnt_kern_flag: <#012x} {mnt.mnt_lflag: <#012x} {vfs.f_fstypename: >6s} " +
2099 "{vfs.f_mntonname: <30s} {vfs.f_mntfromname: <35s} {iomode: <30s}").format(mnt
=mount
, vfs
=mount
.mnt_vfsstat
, iomode
=('Yes' if (mount
.mnt_ioflags
& 0x4) else 'No'))
2102 @lldb_command('showallmounts')
2103 def ShowAllMounts(cmd_args
=None):
2104 """ Print all mount points
2106 mntlist
= kern
.globals.mountlist
2107 print GetMountSummary
.header
2108 for mnt
in IterateTAILQ_HEAD(mntlist
, 'mnt_list'):
2109 print GetMountSummary(mnt
)
2112 lldb_alias('ShowAllVols', 'showallmounts')
2114 @lldb_command('systemlog')
2115 def ShowSystemLog(cmd_args
=None):
2116 """ Display the kernel's printf ring buffer """
2117 msgbufp
= kern
.globals.msgbufp
2118 msg_size
= int(msgbufp
.msg_size
)
2119 msg_bufx
= int(msgbufp
.msg_bufx
)
2120 msg_bufr
= int(msgbufp
.msg_bufr
)
2121 msg_bufc
= msgbufp
.msg_bufc
2122 msg_bufc_data
= msg_bufc
.GetSBValue().GetPointeeData(0, msg_size
)
2124 # the buffer is circular; start at the write pointer to end,
2125 # then from beginning to write pointer
2127 err
= lldb
.SBError()
2128 for i
in range(msg_bufx
, msg_size
) + range(0, msg_bufx
) :
2130 cbyte
= msg_bufc_data
.GetUnsignedInt8(err
, i
)
2131 if not err
.Success() :
2132 raise ValueError("Failed to read character at offset " + str(i
) + ": " + err
.GetCString())
2147 @static_var('output','')
2148 def _GetVnodePathName(vnode
, vnodename
):
2149 """ Internal function to get vnode path string from vnode structure.
2153 returns Nothing. The output will be stored in the static variable.
2157 if int(vnode
.v_flag
) & 0x1 and int(hex(vnode
.v_mount
), 16) !=0:
2158 if int(vnode
.v_mount
.mnt_vnodecovered
):
2159 _GetVnodePathName(vnode
.v_mount
.mnt_vnodecovered
, str(vnode
.v_mount
.mnt_vnodecovered
.v_name
) )
2161 _GetVnodePathName(vnode
.v_parent
, str(vnode
.v_parent
.v_name
))
2162 _GetVnodePathName
.output
+= "/%s" % vnodename
2164 def GetVnodePath(vnode
):
2165 """ Get string representation of the vnode
2166 params: vnodeval - value representing vnode * in the kernel
2167 return: str - of format /path/to/something
2171 if (int(vnode
.v_flag
) & 0x000001) and int(hex(vnode
.v_mount
), 16) != 0 and (int(vnode
.v_mount
.mnt_flag
) & 0x00004000) :
2174 _GetVnodePathName
.output
= ''
2175 if abs(vnode
.v_name
) != 0:
2176 _GetVnodePathName(vnode
, str(vnode
.v_name
))
2177 out_str
+= _GetVnodePathName
.output
2179 out_str
+= 'v_name = NULL'
2180 _GetVnodePathName
.output
= ''
2184 @lldb_command('showvnodepath')
2185 def ShowVnodePath(cmd_args
=None):
2186 """ Prints the path for a vnode
2187 usage: showvnodepath <vnode>
2189 if cmd_args
!= None and len(cmd_args
) > 0 :
2190 vnode_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vnode *')
2192 print GetVnodePath(vnode_val
)
2195 # Macro: showvnodedev
2196 def GetVnodeDevInfo(vnode
):
2197 """ Internal function to get information from the device type vnodes
2198 params: vnode - value representing struct vnode *
2199 return: str - formatted output information for block and char vnode types passed as param
2201 vnodedev_output
= ""
2202 vblk_type
= GetEnumValue('vtype::VBLK')
2203 vchr_type
= GetEnumValue('vtype::VCHR')
2204 if (vnode
.v_type
== vblk_type
) or (vnode
.v_type
== vchr_type
):
2205 devnode
= Cast(vnode
.v_data
, 'devnode_t *')
2206 devnode_dev
= devnode
.dn_typeinfo
.dev
2207 devnode_major
= (devnode_dev
>> 24) & 0xff
2208 devnode_minor
= devnode_dev
& 0x00ffffff
2210 # boilerplate device information for a vnode
2211 vnodedev_output
+= "Device Info:\n\t vnode:\t\t{:#x}".format(vnode
)
2212 vnodedev_output
+= "\n\t type:\t\t"
2213 if (vnode
.v_type
== vblk_type
):
2214 vnodedev_output
+= "VBLK"
2215 if (vnode
.v_type
== vchr_type
):
2216 vnodedev_output
+= "VCHR"
2217 vnodedev_output
+= "\n\t name:\t\t{:<s}".format(vnode
.v_name
)
2218 vnodedev_output
+= "\n\t major, minor:\t{:d},{:d}".format(devnode_major
, devnode_minor
)
2219 vnodedev_output
+= "\n\t mode\t\t0{:o}".format(unsigned(devnode
.dn_mode
))
2220 vnodedev_output
+= "\n\t owner (u,g):\t{:d} {:d}".format(devnode
.dn_uid
, devnode
.dn_gid
)
2222 # decode device specific data
2223 vnodedev_output
+= "\nDevice Specific Information:\t"
2224 if (vnode
.v_type
== vblk_type
):
2225 vnodedev_output
+= "Sorry, I do not know how to decode block devices yet!"
2226 vnodedev_output
+= "\nMaybe you can write me!"
2228 if (vnode
.v_type
== vchr_type
):
2229 # Device information; this is scanty
2231 if (devnode_major
> 42) or (devnode_major
< 0):
2232 vnodedev_output
+= "Invalid major #\n"
2233 # static assignments in conf
2234 elif (devnode_major
== 0):
2235 vnodedev_output
+= "Console mux device\n"
2236 elif (devnode_major
== 2):
2237 vnodedev_output
+= "Current tty alias\n"
2238 elif (devnode_major
== 3):
2239 vnodedev_output
+= "NULL device\n"
2240 elif (devnode_major
== 4):
2241 vnodedev_output
+= "Old pty slave\n"
2242 elif (devnode_major
== 5):
2243 vnodedev_output
+= "Old pty master\n"
2244 elif (devnode_major
== 6):
2245 vnodedev_output
+= "Kernel log\n"
2246 elif (devnode_major
== 12):
2247 vnodedev_output
+= "Memory devices\n"
2248 # Statically linked dynamic assignments
2249 elif unsigned(kern
.globals.cdevsw
[devnode_major
].d_open
) == unsigned(kern
.GetLoadAddressForSymbol('ptmx_open')):
2250 vnodedev_output
+= "Cloning pty master not done\n"
2251 #GetVnodeDevCpty(devnode_major, devnode_minor)
2252 elif unsigned(kern
.globals.cdevsw
[devnode_major
].d_open
) == unsigned(kern
.GetLoadAddressForSymbol('ptsd_open')):
2253 vnodedev_output
+= "Cloning pty slave not done\n"
2254 #GetVnodeDevCpty(devnode_major, devnode_minor)
2256 vnodedev_output
+= "RESERVED SLOT\n"
2258 vnodedev_output
+= "{:#x} is not a device".format(vnode
)
2259 return vnodedev_output
2261 @lldb_command('showvnodedev')
2262 def ShowVnodeDev(cmd_args
=None):
2263 """ Routine to display details of all vnodes of block and character device types
2264 Usage: showvnodedev <address of vnode>
2267 print "No arguments passed"
2268 print ShowVnodeDev
.__doc
__
2270 vnode_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vnode *')
2272 print "unknown arguments:", str(cmd_args
)
2274 print GetVnodeDevInfo(vnode_val
)
2276 # EndMacro: showvnodedev
2278 # Macro: showvnodelocks
2279 def GetVnodeLock(lockf
):
2280 """ Internal function to get information from the given advisory lock
2281 params: lockf - value representing v_lockf member in struct vnode *
2282 return: str - formatted output information for the advisory lock
2284 vnode_lock_output
= ''
2285 lockf_flags
= lockf
.lf_flags
2286 lockf_type
= lockf
.lf_type
2287 if lockf_flags
& 0x20:
2288 vnode_lock_output
+= ("{: <8s}").format('flock')
2289 if lockf_flags
& 0x40:
2290 vnode_lock_output
+= ("{: <8s}").format('posix')
2291 if lockf_flags
& 0x80:
2292 vnode_lock_output
+= ("{: <8s}").format('prov')
2293 if lockf_flags
& 0x10:
2294 vnode_lock_output
+= ("{: <4s}").format('W')
2295 if lockf_flags
& 0x400:
2296 vnode_lock_output
+= ("{: <8s}").format('ofd')
2298 vnode_lock_output
+= ("{: <4s}").format('.')
2300 # POSIX file vs advisory range locks
2301 if lockf_flags
& 0x40:
2302 lockf_proc
= Cast(lockf
.lf_id
, 'proc *')
2303 vnode_lock_output
+= ("PID {: <18d}").format(lockf_proc
.p_pid
)
2305 vnode_lock_output
+= ("ID {: <#019x}").format(int(lockf
.lf_id
))
2309 vnode_lock_output
+= ("{: <12s}").format('shared')
2312 vnode_lock_output
+= ("{: <12s}").format('exclusive')
2315 vnode_lock_output
+= ("{: <12s}").format('unlock')
2317 vnode_lock_output
+= ("{: <12s}").format('unknown')
2319 # start and stop values
2320 vnode_lock_output
+= ("{: #018x} ..").format(lockf
.lf_start
)
2321 vnode_lock_output
+= ("{: #018x}\n").format(lockf
.lf_end
)
2322 return vnode_lock_output
2324 @header("{0: <3s} {1: <7s} {2: <3s} {3: <21s} {4: <11s} {5: ^19s} {6: ^17s}".format('*', 'type', 'W', 'held by', 'lock type', 'start', 'end'))
2325 def GetVnodeLocksSummary(vnode
):
2326 """ Internal function to get summary of advisory locks for the given vnode
2327 params: vnode - value representing the vnode object
2328 return: str - formatted output information for the summary of advisory locks
2332 lockf_list
= vnode
.v_lockf
2333 for lockf_itr
in IterateLinkedList(lockf_list
, 'lf_next'):
2334 out_str
+= ("{: <4s}").format('H')
2335 out_str
+= GetVnodeLock(lockf_itr
)
2336 lockf_blocker
= lockf_itr
.lf_blkhd
.tqh_first
2337 while lockf_blocker
:
2338 out_str
+= ("{: <4s}").format('>')
2339 out_str
+= GetVnodeLock(lockf_blocker
)
2340 lockf_blocker
= lockf_blocker
.lf_block
.tqe_next
2343 @lldb_command('showvnodelocks')
2344 def ShowVnodeLocks(cmd_args
=None):
2345 """ Routine to display list of advisory record locks for the given vnode address
2346 Usage: showvnodelocks <address of vnode>
2349 print "No arguments passed"
2350 print ShowVnodeLocks
.__doc
__
2352 vnode_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vnode *')
2354 print "unknown arguments:", str(cmd_args
)
2356 print GetVnodeLocksSummary
.header
2357 print GetVnodeLocksSummary(vnode_val
)
2359 # EndMacro: showvnodelocks
2361 # Macro: showproclocks
2363 @lldb_command('showproclocks')
2364 def ShowProcLocks(cmd_args
=None):
2365 """ Routine to display list of advisory record locks for the given process
2366 Usage: showproclocks <address of proc>
2369 print "No arguments passed"
2370 print ShowProcLocks
.__doc
__
2372 proc
= kern
.GetValueFromAddress(cmd_args
[0], 'proc *')
2374 print "unknown arguments:", str(cmd_args
)
2377 proc_filedesc
= proc
.p_fd
2378 fd_lastfile
= proc_filedesc
.fd_lastfile
2379 fd_ofiles
= proc_filedesc
.fd_ofiles
2382 while count
<= fd_lastfile
:
2383 if fd_ofiles
[count
]:
2384 fglob
= fd_ofiles
[count
].fp_glob
2385 fo_type
= fglob
.fg_ops
.fo_type
2387 fg_data
= fglob
.fg_data
2388 fg_vnode
= Cast(fg_data
, 'vnode *')
2389 name
= fg_vnode
.v_name
2390 lockf_itr
= fg_vnode
.v_lockf
2393 print GetVnodeLocksSummary
.header
2395 out_str
+= ("\n( fd {:d}, name ").format(count
)
2397 out_str
+= "(null) )\n"
2399 out_str
+= "{:s} )\n".format(name
)
2401 print GetVnodeLocksSummary(fg_vnode
)
2403 print "\n{0: d} total locks for {1: #018x}".format(seen
, proc
)
2405 # EndMacro: showproclocks
2407 @lldb_type_summary(['vnode_t', 'vnode *'])
2408 @header("{0: <20s} {1: >8s} {2: >9s} {3: >8s} {4: <20s} {5: <6s} {6: <20s} {7: <6s} {8: <6s} {9: <35s}".format('vnode', 'usecount', 'kusecount', 'iocount', 'v_data', 'vtype', 'parent', 'mapped', 'cs_version', 'name'))
2409 def GetVnodeSummary(vnode
):
2410 """ Get a summary of important information out of vnode
2413 format_string
= "{0: <#020x} {1: >8d} {2: >8d} {3: >8d} {4: <#020x} {5: <6s} {6: <#020x} {7: <6s} {8: <6s} {9: <35s}"
2414 usecount
= int(vnode
.v_usecount
)
2415 kusecount
= int(vnode
.v_kusecount
)
2416 iocount
= int(vnode
.v_iocount
)
2417 v_data_ptr
= int(hex(vnode
.v_data
), 16)
2418 vtype
= int(vnode
.v_type
)
2419 vtype_str
= "%d" % vtype
2420 vnode_types
= ['VNON', 'VREG', 'VDIR', 'VBLK', 'VCHR', 'VLNK', 'VSOCK', 'VFIFO', 'VBAD', 'VSTR', 'VCPLX'] # see vnode.h for enum type definition
2421 if vtype
>= 0 and vtype
< len(vnode_types
):
2422 vtype_str
= vnode_types
[vtype
]
2423 parent_ptr
= int(hex(vnode
.v_parent
), 16)
2424 name_ptr
= int(hex(vnode
.v_name
), 16)
2427 name
= str(vnode
.v_name
)
2428 elif int(vnode
.v_tag
) == 16 :
2429 cnode
= Cast(vnode
.v_data
, 'cnode *')
2430 name
= "hfs: %s" % str( Cast(cnode
.c_desc
.cd_nameptr
, 'char *'))
2432 csblob_version
= '-'
2433 if (vtype
== 1) and (vnode
.v_un
.vu_ubcinfo
!= 0):
2434 csblob_version
= '{: <6d}'.format(vnode
.v_un
.vu_ubcinfo
.cs_add_gen
)
2435 # Check to see if vnode is mapped/unmapped
2436 if (vnode
.v_un
.vu_ubcinfo
.ui_flags
& 0x8) != 0:
2440 out_str
+= format_string
.format(vnode
, usecount
, kusecount
, iocount
, v_data_ptr
, vtype_str
, parent_ptr
, mapped
, csblob_version
, name
)
2443 @lldb_command('showallvnodes')
2444 def ShowAllVnodes(cmd_args
=None):
2445 """ Display info about all vnodes
2447 mntlist
= kern
.globals.mountlist
2448 print GetVnodeSummary
.header
2449 for mntval
in IterateTAILQ_HEAD(mntlist
, 'mnt_list'):
2450 for vnodeval
in IterateTAILQ_HEAD(mntval
.mnt_vnodelist
, 'v_mntvnodes'):
2451 print GetVnodeSummary(vnodeval
)
2454 @lldb_command('showvnode')
2455 def ShowVnode(cmd_args
=None):
2456 """ Display info about one vnode
2457 usage: showvnode <vnode>
2459 if cmd_args
== None or len(cmd_args
) < 1:
2460 print "Please provide valid vnode argument. Type help showvnode for help."
2462 vnodeval
= kern
.GetValueFromAddress(cmd_args
[0],'vnode *')
2463 print GetVnodeSummary
.header
2464 print GetVnodeSummary(vnodeval
)
2466 @lldb_command('showvolvnodes')
2467 def ShowVolVnodes(cmd_args
=None):
2468 """ Display info about all vnodes of a given mount_t
2470 if cmd_args
== None or len(cmd_args
) < 1:
2471 print "Please provide a valide mount_t argument. Try 'help showvolvnodes' for help"
2473 mntval
= kern
.GetValueFromAddress(cmd_args
[0], 'mount_t')
2474 print GetVnodeSummary
.header
2475 for vnodeval
in IterateTAILQ_HEAD(mntval
.mnt_vnodelist
, 'v_mntvnodes'):
2476 print GetVnodeSummary(vnodeval
)
2479 @lldb_command('showvolbusyvnodes')
2480 def ShowVolBusyVnodes(cmd_args
=None):
2481 """ Display info about busy (iocount!=0) vnodes of a given mount_t
2483 if cmd_args
== None or len(cmd_args
) < 1:
2484 print "Please provide a valide mount_t argument. Try 'help showvolbusyvnodes' for help"
2486 mntval
= kern
.GetValueFromAddress(cmd_args
[0], 'mount_t')
2487 print GetVnodeSummary
.header
2488 for vnodeval
in IterateTAILQ_HEAD(mntval
.mnt_vnodelist
, 'v_mntvnodes'):
2489 if int(vnodeval
.v_iocount
) != 0:
2490 print GetVnodeSummary(vnodeval
)
2492 @lldb_command('showallbusyvnodes')
2493 def ShowAllBusyVnodes(cmd_args
=None):
2494 """ Display info about all busy (iocount!=0) vnodes
2496 mntlistval
= kern
.globals.mountlist
2497 for mntval
in IterateTAILQ_HEAD(mntlistval
, 'mnt_list'):
2498 ShowVolBusyVnodes([hex(mntval
)])
2500 @lldb_command('print_vnode')
2501 def PrintVnode(cmd_args
=None):
2502 """ Prints out the fields of a vnode struct
2503 Usage: print_vnode <vnode>
2506 print "Please provide valid vnode argument. Type help print_vnode for help."
2510 @lldb_command('showworkqvnodes')
2511 def ShowWorkqVnodes(cmd_args
=None):
2512 """ Print the vnode worker list
2513 Usage: showworkqvnodes <struct mount *>
2516 print "Please provide valid mount argument. Type help showworkqvnodes for help."
2519 mp
= kern
.GetValueFromAddress(cmd_args
[0], 'mount *')
2520 vp
= Cast(mp
.mnt_workerqueue
.tqh_first
, 'vnode *')
2521 print GetVnodeSummary
.header
2523 print GetVnodeSummary(vp
)
2524 vp
= vp
.v_mntvnodes
.tqe_next
2526 @lldb_command('shownewvnodes')
2527 def ShowNewVnodes(cmd_args
=None):
2528 """ Print the new vnode list
2529 Usage: shownewvnodes <struct mount *>
2532 print "Please provide valid mount argument. Type help shownewvnodes for help."
2534 mp
= kern
.GetValueFromAddress(cmd_args
[0], 'mount *')
2535 vp
= Cast(mp
.mnt_newvnodes
.tqh_first
, 'vnode *')
2536 print GetVnodeSummary
.header
2538 print GetVnodeSummary(vp
)
2539 vp
= vp
.v_mntvnodes
.tqe_next
2542 @lldb_command('showprocvnodes')
2543 def ShowProcVnodes(cmd_args
=None):
2544 """ Routine to print out all the open fds which are vnodes in a process
2545 Usage: showprocvnodes <proc *>
2548 print "Please provide valid proc argument. Type help showprocvnodes for help."
2550 procptr
= kern
.GetValueFromAddress(cmd_args
[0], 'proc *')
2551 fdptr
= Cast(procptr
.p_fd
, 'filedesc *')
2552 if int(fdptr
.fd_cdir
) != 0:
2553 print '{0: <25s}\n{1: <s}\n{2: <s}'.format('Current Working Directory:', GetVnodeSummary
.header
, GetVnodeSummary(fdptr
.fd_cdir
))
2554 if int(fdptr
.fd_rdir
) != 0:
2555 print '{0: <25s}\n{1: <s}\n{2: <s}'.format('Current Root Directory:', GetVnodeSummary
.header
, GetVnodeSummary(fdptr
.fd_rdir
))
2557 print '\n' + '{0: <5s} {1: <7s} {2: <20s} '.format('fd', 'flags', 'fileglob') + GetVnodeSummary
.header
2558 # Hack to get around <rdar://problem/12879494> llb fails to cast addresses to double pointers
2559 fpptr
= Cast(fdptr
.fd_ofiles
, 'uint64_t *')
2560 while count
< fdptr
.fd_nfiles
:
2561 fpp
= dereference(fpptr
)
2562 fproc
= kern
.GetValueFromAddress(int(fpp
), 'fileproc *')
2564 fglob
= dereference(fproc
).fp_glob
2566 if (int(fglob
) != 0) and (int(fglob
.fg_ops
.fo_type
) == 1):
2567 if (fdptr
.fd_ofileflags
[count
] & 1): flags
+= 'E'
2568 if (fdptr
.fd_ofileflags
[count
] & 2): flags
+= 'F'
2569 if (fdptr
.fd_ofileflags
[count
] & 4): flags
+= 'R'
2570 if (fdptr
.fd_ofileflags
[count
] & 8): flags
+= 'C'
2571 print '{0: <5d} {1: <7s} {2: <#020x} '.format(count
, flags
, fglob
) + GetVnodeSummary(Cast(fglob
.fg_data
, 'vnode *'))
2573 fpptr
= kern
.GetValueFromAddress(int(fpptr
) + kern
.ptrsize
,'uint64_t *')
2575 @lldb_command('showallprocvnodes')
2576 def ShowAllProcVnodes(cmd_args
=None):
2577 """ Routine to print out all the open fds which are vnodes
2580 procptr
= Cast(kern
.globals.allproc
.lh_first
, 'proc *')
2581 while procptr
and int(procptr
) != 0:
2582 print '{:<s}'.format("=" * 106)
2583 print GetProcInfo(procptr
)
2584 ShowProcVnodes([int(procptr
)])
2585 procptr
= procptr
.p_list
.le_next
2587 @xnudebug_test('test_vnode')
2588 def TestShowAllVnodes(kernel_target
, config
, lldb_obj
, isConnected
):
2589 """ Test the functionality of vnode related commands
2595 print "Target is not connected. Cannot test memstats"
2597 res
= lldb
.SBCommandReturnObject()
2598 lldb_obj
.debugger
.GetCommandInterpreter().HandleCommand("showallvnodes", res
)
2599 result
= res
.GetOutput()
2600 if len(result
.split("\n")) > 2 and result
.find('VREG') != -1 and len(result
.splitlines()[2].split()) > 5:
2606 @lldb_type_summary(['_lck_grp_ *'])
2607 def GetMutexEntry(mtxg
):
2608 """ Summarize a mutex group entry with important information.
2610 mtxg: value - obj representing a mutex group in kernel
2612 out_string - summary of the mutex group
2616 if kern
.ptrsize
== 8:
2617 format_string
= '{0:#018x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
2619 format_string
= '{0:#010x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
2621 if mtxg
.lck_grp_mtxcnt
:
2622 out_string
+= format_string
.format(mtxg
, mtxg
.lck_grp_mtxcnt
,mtxg
.lck_grp_stat
.lck_grp_mtx_stat
.lck_grp_mtx_util_cnt
,
2623 mtxg
.lck_grp_stat
.lck_grp_mtx_stat
.lck_grp_mtx_miss_cnt
,
2624 mtxg
.lck_grp_stat
.lck_grp_mtx_stat
.lck_grp_mtx_wait_cnt
, mtxg
.lck_grp_name
)
2627 @lldb_command('showallmtx')
2628 def ShowAllMtx(cmd_args
=None):
2629 """ Routine to print a summary listing of all mutexes
2632 if kern
.ptrsize
== 8:
2633 hdr_format
= '{:<18s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
2635 hdr_format
= '{:<10s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
2637 print hdr_format
.format('LCK GROUP', 'CNT', 'UTIL', 'MISS', 'WAIT', 'NAME')
2639 mtxgrp_queue_head
= kern
.globals.lck_grp_queue
2640 mtxgrp_ptr_type
= GetType('_lck_grp_ *')
2642 for mtxgrp_ptr
in IterateQueue(mtxgrp_queue_head
, mtxgrp_ptr_type
, "lck_grp_link"):
2643 print GetMutexEntry(mtxgrp_ptr
)
2645 # EndMacro: showallmtx
2647 # Macro: showallrwlck
2648 @lldb_type_summary(['_lck_grp_ *'])
2649 def GetRWLEntry(rwlg
):
2650 """ Summarize a reader writer lock group with important information.
2652 rwlg: value - obj representing a reader writer lock group in kernel
2654 out_string - summary of the reader writer lock group
2658 if kern
.ptrsize
== 8:
2659 format_string
= '{0:#018x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
2661 format_string
= '{0:#010x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
2663 if rwlg
.lck_grp_rwcnt
:
2664 out_string
+= format_string
.format(rwlg
, rwlg
.lck_grp_rwcnt
,rwlg
.lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_util_cnt
,
2665 rwlg
.lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_miss_cnt
,
2666 rwlg
.lck_grp_stat
.lck_grp_rw_stat
.lck_grp_rw_wait_cnt
, rwlg
.lck_grp_name
)
2670 @lldb_type_summary(['lck_mtx_t *'])
2671 @header("===== Mutex Lock Summary =====")
2672 def GetMutexLockSummary(mtx
):
2673 """ Summarize mutex lock with important information.
2675 mtx: value - obj representing a mutex lock in kernel
2677 out_str - summary of the mutex lock
2680 return "Invalid lock value: 0x0"
2682 if kern
.arch
== "x86_64":
2683 out_str
= "Lock Type : MUTEX\n"
2684 if mtx
.lck_mtx_tag
== 0x07ff1007 :
2685 out_str
+= "Tagged as indirect, printing ext lock at: {:#x}\n".format(mtx
.lck_mtx_ptr
)
2686 mtx
= Cast(mtx
.lck_mtx_ptr
, 'lck_mtx_t *')
2688 if mtx
.lck_mtx_tag
== 0x07fe2007 :
2689 out_str
+= "*** Tagged as DESTROYED ({:#x}) ***\n".format(mtx
.lck_mtx_tag
)
2691 out_str
+= "Owner Thread : {mtx.lck_mtx_owner:#x}\n".format(mtx
=mtx
)
2692 out_str
+= "Number of Waiters : {mtx.lck_mtx_waiters:#x}\n".format(mtx
=mtx
)
2693 out_str
+= "ILocked : {mtx.lck_mtx_ilocked:#x}\n".format(mtx
=mtx
)
2694 out_str
+= "MLocked : {mtx.lck_mtx_mlocked:#x}\n".format(mtx
=mtx
)
2695 out_str
+= "Promoted : {mtx.lck_mtx_promoted:#x}\n".format(mtx
=mtx
)
2696 out_str
+= "Pri : {mtx.lck_mtx_pri:#x}\n".format(mtx
=mtx
)
2697 out_str
+= "Spin : {mtx.lck_mtx_spin:#x}\n".format(mtx
=mtx
)
2698 out_str
+= "Ext : {mtx.lck_mtx_is_ext:#x}\n".format(mtx
=mtx
)
2699 if mtx
.lck_mtx_pad32
== 0xFFFFFFFF :
2700 out_str
+= "Canary (valid) : {mtx.lck_mtx_pad32:#x}\n".format(mtx
=mtx
)
2702 out_str
+= "Canary (INVALID) : {mtx.lck_mtx_pad32:#x}\n".format(mtx
=mtx
)
2705 out_str
= "Lock Type\t\t: MUTEX\n"
2706 out_str
+= "Owner Thread\t\t: {:#x}".format(mtx
.lck_mtx_data
& ~
0x3)
2707 if (mtx
.lck_mtx_data
& ~
0x3) == 0xfffffff0:
2708 out_str
+= " Held as spinlock"
2709 out_str
+= "\nNumber of Waiters\t: {:d}\n".format(mtx
.lck_mtx_waiters
)
2710 out_str
+= "Flags\t\t\t: "
2711 if mtx
.lck_mtx_data
& 0x1:
2712 out_str
+= "[Interlock Locked] "
2713 if mtx
.lck_mtx_data
& 0x2:
2714 out_str
+= "[Wait Flag]"
2717 @lldb_type_summary(['lck_spin_t *'])
2718 @header("===== SpinLock Summary =====")
2719 def GetSpinLockSummary(spinlock
):
2720 """ Summarize spinlock with important information.
2722 spinlock: value - obj representing a spinlock in kernel
2724 out_str - summary of the spinlock
2727 return "Invalid lock value: 0x0"
2729 out_str
= "Lock Type\t\t: SPINLOCK\n"
2730 if kern
.arch
== "x86_64":
2731 out_str
+= "Interlock\t\t: {:#x}\n".format(spinlock
.interlock
)
2734 lock_data
= spinlock
.hwlock
.lock_data
2736 out_str
+= "Invalid state: interlock is locked but no owner\n"
2738 out_str
+= "Owner Thread\t\t: "
2742 out_str
+= "{:#x}\n".format(lock_data
& ~
0x1)
2743 if (lock_data
& 1) == 0:
2744 out_str
+= "Invalid state: owned but interlock bit is not set\n"
2747 @lldb_command('showlock', 'MS')
2748 def ShowLock(cmd_args
=None, cmd_options
={}):
2749 """ Show info about a lock - its state and owner thread details
2750 Usage: showlock <address of a lock>
2751 -M : to consider <addr> as lck_mtx_t
2752 -S : to consider <addr> as lck_spin_t
2755 raise ArgumentError("Please specify the address of the lock whose info you want to view.")
2760 # from osfmk/arm/locks.h
2761 LCK_SPIN_TYPE
= 0x11
2763 if kern
.arch
== "x86_64":
2764 if "-M" in cmd_options
:
2765 lock_mtx
= kern
.GetValueFromAddress(addr
, 'lck_mtx_t *')
2766 summary_str
= GetMutexLockSummary(lock_mtx
)
2767 elif "-S" in cmd_options
:
2768 lock_spin
= kern
.GetValueFromAddress(addr
, 'lck_spin_t *')
2769 summary_str
= GetSpinLockSummary(lock_spin
)
2771 summary_str
= "Please specify supported lock option(-M/-S)"
2775 lock
= kern
.GetValueFromAddress(addr
, 'uintptr_t *')
2777 lock_mtx
= Cast(lock
, 'lck_mtx_t*')
2778 if lock_mtx
.lck_mtx_type
== LCK_MTX_TYPE
:
2779 summary_str
= GetMutexLockSummary(lock_mtx
)
2781 lock_spin
= Cast(lock
, 'lck_spin_t*')
2782 if lock_spin
.type == LCK_SPIN_TYPE
:
2783 summary_str
= GetSpinLockSummary(lock_spin
)
2784 if summary_str
== "":
2785 summary_str
= "Lock Type\t\t: INVALID LOCK"
2790 @lldb_command('showallrwlck')
2791 def ShowAllRWLck(cmd_args
=None):
2792 """ Routine to print a summary listing of all read/writer locks
2794 if kern
.ptrsize
== 8:
2795 hdr_format
= '{:<18s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
2797 hdr_format
= '{:<10s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
2799 print hdr_format
.format('LCK GROUP', 'CNT', 'UTIL', 'MISS', 'WAIT', 'NAME')
2801 rwlgrp_queue_head
= kern
.globals.lck_grp_queue
2802 rwlgrp_ptr_type
= GetType('_lck_grp_ *')
2803 for rwlgrp_ptr
in IterateQueue(rwlgrp_queue_head
, rwlgrp_ptr_type
, "lck_grp_link"):
2804 print GetRWLEntry(rwlgrp_ptr
)
2806 # EndMacro: showallrwlck
2808 #Macro: showbootermemorymap
2809 @lldb_command('showbootermemorymap')
2810 def ShowBooterMemoryMap(cmd_args
=None):
2811 """ Prints out the phys memory map from kernelBootArgs
2812 Supported only on x86_64
2814 if kern
.arch
!= 'x86_64':
2815 print "showbootermemorymap not supported on this architecture"
2838 boot_args
= kern
.globals.kernelBootArgs
2839 msize
= boot_args
.MemoryMapDescriptorSize
2840 mcount
= (boot_args
.MemoryMapSize
) / unsigned(msize
)
2842 out_string
+= "{0: <12s} {1: <19s} {2: <19s} {3: <19s} {4: <10s}\n".format("Type", "Physical Start", "Number of Pages", "Virtual Start", "Attributes")
2846 mptr
= kern
.GetValueFromAddress(unsigned(boot_args
.MemoryMap
) + kern
.VM_MIN_KERNEL_ADDRESS
+ unsigned(i
*msize
), 'EfiMemoryRange *')
2847 mtype
= unsigned(mptr
.Type
)
2848 if mtype
in memtype_dict
:
2849 out_string
+= "{0: <12s}".format(memtype_dict
[mtype
])
2851 out_string
+= "{0: <12s}".format("UNKNOWN")
2853 if mptr
.VirtualStart
== 0:
2854 out_string
+= "{0: #019x} {1: #019x} {2: <19s} {3: #019x}\n".format(mptr
.PhysicalStart
, mptr
.NumberOfPages
, ' '*19, mptr
.Attribute
)
2856 out_string
+= "{0: #019x} {1: #019x} {2: #019x} {3: #019x}\n".format(mptr
.PhysicalStart
, mptr
.NumberOfPages
, mptr
.VirtualStart
, mptr
.Attribute
)
2860 #EndMacro: showbootermemorymap
2862 @lldb_command('show_all_purgeable_objects')
2863 def ShowAllPurgeableVmObjects(cmd_args
=None):
2864 """ Routine to print a summary listing of all the purgeable vm objects
2866 print "\n-------------------- VOLATILE OBJECTS --------------------\n"
2867 ShowAllPurgeableVolatileVmObjects()
2868 print "\n-------------------- NON-VOLATILE OBJECTS --------------------\n"
2869 ShowAllPurgeableNonVolatileVmObjects()
2871 @lldb_command('show_all_purgeable_nonvolatile_objects')
2872 def ShowAllPurgeableNonVolatileVmObjects(cmd_args
=None):
2873 """ Routine to print a summary listing of all the vm objects in
2874 the purgeable_nonvolatile_queue
2877 nonvolatile_total
= lambda:None
2878 nonvolatile_total
.objects
= 0
2879 nonvolatile_total
.vsize
= 0
2880 nonvolatile_total
.rsize
= 0
2881 nonvolatile_total
.wsize
= 0
2882 nonvolatile_total
.csize
= 0
2883 nonvolatile_total
.disowned_objects
= 0
2884 nonvolatile_total
.disowned_vsize
= 0
2885 nonvolatile_total
.disowned_rsize
= 0
2886 nonvolatile_total
.disowned_wsize
= 0
2887 nonvolatile_total
.disowned_csize
= 0
2889 queue_len
= kern
.globals.purgeable_nonvolatile_count
2890 queue_head
= kern
.globals.purgeable_nonvolatile_queue
2892 print 'purgeable_nonvolatile_queue:{: <#018x} purgeable_volatile_count:{:d}\n'.format(kern
.GetLoadAddressForSymbol('purgeable_nonvolatile_queue'),queue_len
)
2893 print 'N:non-volatile V:volatile E:empty D:deny\n'
2895 print '{:>6s} {:<6s} {:18s} {:1s} {:>6s} {:>16s} {:>10s} {:>10s} {:>10s} {:>3s} {:18s} {:>6s} {:<20s}\n'.format("#","#","object","P","refcnt","size (pages)","resid","wired","compressed","tag","owner","pid","process")
2897 for object in IterateQueue(queue_head
, 'struct vm_object *', 'objq'):
2899 ShowPurgeableNonVolatileVmObject(object, idx
, queue_len
, nonvolatile_total
)
2900 print "disowned objects:{:<10d} [ virtual:{:<10d} resident:{:<10d} wired:{:<10d} compressed:{:<10d} ]\n".format(nonvolatile_total
.disowned_objects
, nonvolatile_total
.disowned_vsize
, nonvolatile_total
.disowned_rsize
, nonvolatile_total
.disowned_wsize
, nonvolatile_total
.disowned_csize
)
2901 print " all objects:{:<10d} [ virtual:{:<10d} resident:{:<10d} wired:{:<10d} compressed:{:<10d} ]\n".format(nonvolatile_total
.objects
, nonvolatile_total
.vsize
, nonvolatile_total
.rsize
, nonvolatile_total
.wsize
, nonvolatile_total
.csize
)
2904 def ShowPurgeableNonVolatileVmObject(object, idx
, queue_len
, nonvolatile_total
):
2905 """ Routine to print out a summary a VM object in purgeable_nonvolatile_queue
2907 object - core.value : a object of type 'struct vm_object *'
2911 page_size
= kern
.globals.page_size
2912 if object.purgable
== 0:
2914 elif object.purgable
== 1:
2916 elif object.purgable
== 2:
2918 elif object.purgable
== 3:
2922 if object.pager
== 0:
2923 compressed_count
= 0
2925 compressor_pager
= Cast(object.pager
, 'compressor_pager *')
2926 compressed_count
= compressor_pager
.cpgr_num_slots_occupied
2928 print "{:>6d}/{:<6d} {: <#018x} {:1s} {:>6d} {:>16d} {:>10d} {:>10d} {:>10d} {:>3d} {: <#018x} {:>6d} {:<20s}\n".format(idx
,queue_len
,object,purgable
,object.ref_count
,object.vo_un1
.vou_size
/page_size
,object.resident_page_count
,object.wired_page_count
,compressed_count
, object.vo_ledger_tag
, object.vo_un2
.vou_owner
,GetProcPIDForObjectOwner(object.vo_un2
.vou_owner
),GetProcNameForObjectOwner(object.vo_un2
.vou_owner
))
2930 nonvolatile_total
.objects
+= 1
2931 nonvolatile_total
.vsize
+= object.vo_un1
.vou_size
/page_size
2932 nonvolatile_total
.rsize
+= object.resident_page_count
2933 nonvolatile_total
.wsize
+= object.wired_page_count
2934 nonvolatile_total
.csize
+= compressed_count
2935 if object.vo_un2
.vou_owner
== 0:
2936 nonvolatile_total
.disowned_objects
+= 1
2937 nonvolatile_total
.disowned_vsize
+= object.vo_un1
.vou_size
/page_size
2938 nonvolatile_total
.disowned_rsize
+= object.resident_page_count
2939 nonvolatile_total
.disowned_wsize
+= object.wired_page_count
2940 nonvolatile_total
.disowned_csize
+= compressed_count
2943 @lldb_command('show_all_purgeable_volatile_objects')
2944 def ShowAllPurgeableVolatileVmObjects(cmd_args
=None):
2945 """ Routine to print a summary listing of all the vm objects in
2946 the purgeable queues
2948 volatile_total
= lambda:None
2949 volatile_total
.objects
= 0
2950 volatile_total
.vsize
= 0
2951 volatile_total
.rsize
= 0
2952 volatile_total
.wsize
= 0
2953 volatile_total
.csize
= 0
2954 volatile_total
.disowned_objects
= 0
2955 volatile_total
.disowned_vsize
= 0
2956 volatile_total
.disowned_rsize
= 0
2957 volatile_total
.disowned_wsize
= 0
2958 volatile_total
.disowned_csize
= 0
2960 purgeable_queues
= kern
.globals.purgeable_queues
2961 print "---------- OBSOLETE\n"
2962 ShowPurgeableQueue(purgeable_queues
[0], volatile_total
)
2963 print "\n\n---------- FIFO\n"
2964 ShowPurgeableQueue(purgeable_queues
[1], volatile_total
)
2965 print "\n\n---------- LIFO\n"
2966 ShowPurgeableQueue(purgeable_queues
[2], volatile_total
)
2968 print "disowned objects:{:<10d} [ virtual:{:<10d} resident:{:<10d} wired:{:<10d} compressed:{:<10d} ]\n".format(volatile_total
.disowned_objects
, volatile_total
.disowned_vsize
, volatile_total
.disowned_rsize
, volatile_total
.disowned_wsize
, volatile_total
.disowned_csize
)
2969 print " all objects:{:<10d} [ virtual:{:<10d} resident:{:<10d} wired:{:<10d} compressed:{:<10d} ]\n".format(volatile_total
.objects
, volatile_total
.vsize
, volatile_total
.rsize
, volatile_total
.wsize
, volatile_total
.csize
)
2970 purgeable_count
= kern
.globals.vm_page_purgeable_count
2971 purgeable_wired_count
= kern
.globals.vm_page_purgeable_wired_count
2972 if purgeable_count
!= volatile_total
.rsize
or purgeable_wired_count
!= volatile_total
.wsize
:
2973 mismatch
= "<--------- MISMATCH\n"
2976 print "vm_page_purgeable_count: resident:{:<10d} wired:{:<10d} {:s}\n".format(purgeable_count
, purgeable_wired_count
, mismatch
)
2979 def ShowPurgeableQueue(qhead
, volatile_total
):
2980 print "----- GROUP 0\n"
2981 ShowPurgeableGroup(qhead
.objq
[0], volatile_total
)
2982 print "----- GROUP 1\n"
2983 ShowPurgeableGroup(qhead
.objq
[1], volatile_total
)
2984 print "----- GROUP 2\n"
2985 ShowPurgeableGroup(qhead
.objq
[2], volatile_total
)
2986 print "----- GROUP 3\n"
2987 ShowPurgeableGroup(qhead
.objq
[3], volatile_total
)
2988 print "----- GROUP 4\n"
2989 ShowPurgeableGroup(qhead
.objq
[4], volatile_total
)
2990 print "----- GROUP 5\n"
2991 ShowPurgeableGroup(qhead
.objq
[5], volatile_total
)
2992 print "----- GROUP 6\n"
2993 ShowPurgeableGroup(qhead
.objq
[6], volatile_total
)
2994 print "----- GROUP 7\n"
2995 ShowPurgeableGroup(qhead
.objq
[7], volatile_total
)
2997 def ShowPurgeableGroup(qhead
, volatile_total
):
2999 for object in IterateQueue(qhead
, 'struct vm_object *', 'objq'):
3001 # print "{:>6s} {:18s} {:1s} {:>6s} {:>16s} {:>10s} {:>10s} {:>10s} {:18s} {:>6s} {:<20s} {:18s} {:>6s} {:<20s} {:s}\n".format("#","object","P","refcnt","size (pages)","resid","wired","compressed","owner","pid","process","volatilizer","pid","process","")
3002 print "{:>6s} {:18s} {:1s} {:>6s} {:>16s} {:>10s} {:>10s} {:>10s} {:>3s} {:18s} {:>6s} {:<20s}\n".format("#","object","P","refcnt","size (pages)","resid","wired","compressed","tag","owner","pid","process")
3004 ShowPurgeableVolatileVmObject(object, idx
, volatile_total
)
3006 def ShowPurgeableVolatileVmObject(object, idx
, volatile_total
):
3007 """ Routine to print out a summary a VM object in a purgeable queue
3009 object - core.value : a object of type 'struct vm_object *'
3013 ## if int(object.vo_un2.vou_owner) != int(object.vo_purgeable_volatilizer):
3017 page_size
= kern
.globals.page_size
3018 if object.purgable
== 0:
3020 elif object.purgable
== 1:
3022 elif object.purgable
== 2:
3024 elif object.purgable
== 3:
3028 if object.pager
== 0:
3029 compressed_count
= 0
3031 compressor_pager
= Cast(object.pager
, 'compressor_pager *')
3032 compressed_count
= compressor_pager
.cpgr_num_slots_occupied
3033 # print "{:>6d} {: <#018x} {:1s} {:>6d} {:>16d} {:>10d} {:>10d} {:>10d} {: <#018x} {:>6d} {:<20s} {: <#018x} {:>6d} {:<20s} {:s}\n".format(idx,object,purgable,object.ref_count,object.vo_un1.vou_size/page_size,object.resident_page_count,object.wired_page_count,compressed_count,object.vo_un2.vou_owner,GetProcPIDForObjectOwner(object.vo_un2.vou_owner),GetProcNameForObjectOwner(object.vo_un2.vou_owner),object.vo_purgeable_volatilizer,GetProcPIDForObjectOwner(object.vo_purgeable_volatilizer),GetProcNameForObjectOwner(object.vo_purgeable_volatilizer),diff)
3034 print "{:>6d} {: <#018x} {:1s} {:>6d} {:>16d} {:>10d} {:>10d} {:>10d} {:>3d} {: <#018x} {:>6d} {:<20s}\n".format(idx
,object,purgable
,object.ref_count
,object.vo_un1
.vou_size
/page_size
,object.resident_page_count
,object.wired_page_count
,compressed_count
, object.vo_ledger_tag
, object.vo_un2
.vou_owner
,GetProcPIDForObjectOwner(object.vo_un2
.vou_owner
),GetProcNameForObjectOwner(object.vo_un2
.vou_owner
))
3035 volatile_total
.objects
+= 1
3036 volatile_total
.vsize
+= object.vo_un1
.vou_size
/page_size
3037 volatile_total
.rsize
+= object.resident_page_count
3038 volatile_total
.wsize
+= object.wired_page_count
3039 volatile_total
.csize
+= compressed_count
3040 if object.vo_un2
.vou_owner
== 0:
3041 volatile_total
.disowned_objects
+= 1
3042 volatile_total
.disowned_vsize
+= object.vo_un1
.vou_size
/page_size
3043 volatile_total
.disowned_rsize
+= object.resident_page_count
3044 volatile_total
.disowned_wsize
+= object.wired_page_count
3045 volatile_total
.disowned_csize
+= compressed_count
3048 def GetCompressedPagesForObject(obj
):
3051 pager
= Cast(obj
.pager
, 'compressor_pager_t')
3052 return pager
.cpgr_num_slots_occupied
3053 """ # commented code below
3054 if pager.cpgr_num_slots > 128:
3055 slots_arr = pager.cpgr_slots.cpgr_islots
3056 num_indirect_slot_ptr = (pager.cpgr_num_slots + 127) / 128
3059 compressed_pages = 0
3060 while index < num_indirect_slot_ptr:
3062 if slots_arr[index]:
3063 while compressor_slot < 128:
3064 if slots_arr[index][compressor_slot]:
3065 compressed_pages += 1
3066 compressor_slot += 1
3069 slots_arr = pager.cpgr_slots.cpgr_dslots
3071 compressed_pages = 0
3072 while compressor_slot < pager.cpgr_num_slots:
3073 if slots_arr[compressor_slot]:
3074 compressed_pages += 1
3075 compressor_slot += 1
3076 return compressed_pages
3079 def ShowTaskVMEntries(task
, show_pager_info
, show_all_shadows
):
3080 """ Routine to print out a summary listing of all the entries in a vm_map
3082 task - core.value : a object of type 'task *'
3086 print "vm_map entries for task " + hex(task
)
3087 print GetTaskSummary
.header
3088 print GetTaskSummary(task
)
3090 print "Task {0: <#020x} has map = 0x0"
3092 showmapvme(task
.map, 0, 0, show_pager_info
, show_all_shadows
, False)
3094 @lldb_command("showmapvme", "A:B:F:PRST")
3095 def ShowMapVME(cmd_args
=None, cmd_options
={}):
3096 """Routine to print out info about the specified vm_map and its vm entries
3097 usage: showmapvme <vm_map> [-A start] [-B end] [-S] [-P]
3098 Use -A <start> flag to start at virtual address <start>
3099 Use -B <end> flag to end at virtual address <end>
3100 Use -F <virtaddr> flag to find just the VME containing the given VA
3101 Use -S flag to show VM object shadow chains
3102 Use -P flag to show pager info (mapped file, compressed pages, ...)
3103 Use -R flag to reverse order
3104 Use -T to show red-black tree pointers
3106 if cmd_args
== None or len(cmd_args
) < 1:
3107 print "Invalid argument.", ShowMapVME
.__doc
__
3109 show_pager_info
= False
3110 show_all_shadows
= False
3111 show_rb_tree
= False
3114 reverse_order
= False
3115 if "-A" in cmd_options
:
3116 start_vaddr
= unsigned(int(cmd_options
['-A'], 16))
3117 if "-B" in cmd_options
:
3118 end_vaddr
= unsigned(int(cmd_options
['-B'], 16))
3119 if "-F" in cmd_options
:
3120 start_vaddr
= unsigned(int(cmd_options
['-F'], 16))
3121 end_vaddr
= start_vaddr
3122 if "-P" in cmd_options
:
3123 show_pager_info
= True
3124 if "-S" in cmd_options
:
3125 show_all_shadows
= True
3126 if "-R" in cmd_options
:
3127 reverse_order
= True
3128 if "-T" in cmd_options
:
3130 map = kern
.GetValueFromAddress(cmd_args
[0], 'vm_map_t')
3131 showmapvme(map, start_vaddr
, end_vaddr
, show_pager_info
, show_all_shadows
, reverse_order
, show_rb_tree
)
3133 @lldb_command("showmapcopyvme", "A:B:F:PRST")
3134 def ShowMapCopyVME(cmd_args
=None, cmd_options
={}):
3135 """Routine to print out info about the specified vm_map_copy and its vm entries
3136 usage: showmapcopyvme <vm_map_copy> [-A start] [-B end] [-S] [-P]
3137 Use -A <start> flag to start at virtual address <start>
3138 Use -B <end> flag to end at virtual address <end>
3139 Use -F <virtaddr> flag to find just the VME containing the given VA
3140 Use -S flag to show VM object shadow chains
3141 Use -P flag to show pager info (mapped file, compressed pages, ...)
3142 Use -R flag to reverse order
3143 Use -T to show red-black tree pointers
3145 if cmd_args
== None or len(cmd_args
) < 1:
3146 print "Invalid argument.", ShowMapVME
.__doc
__
3148 show_pager_info
= False
3149 show_all_shadows
= False
3150 show_rb_tree
= False
3153 reverse_order
= False
3154 if "-A" in cmd_options
:
3155 start_vaddr
= unsigned(int(cmd_options
['-A'], 16))
3156 if "-B" in cmd_options
:
3157 end_vaddr
= unsigned(int(cmd_options
['-B'], 16))
3158 if "-F" in cmd_options
:
3159 start_vaddr
= unsigned(int(cmd_options
['-F'], 16))
3160 end_vaddr
= start_vaddr
3161 if "-P" in cmd_options
:
3162 show_pager_info
= True
3163 if "-S" in cmd_options
:
3164 show_all_shadows
= True
3165 if "-R" in cmd_options
:
3166 reverse_order
= True
3167 if "-T" in cmd_options
:
3169 map = kern
.GetValueFromAddress(cmd_args
[0], 'vm_map_copy_t')
3170 showmapcopyvme(map, start_vaddr
, end_vaddr
, show_pager_info
, show_all_shadows
, reverse_order
, show_rb_tree
)
3172 @lldb_command("showvmobject", "A:B:PRST")
3173 def ShowVMObject(cmd_args
=None, cmd_options
={}):
3174 """Routine to print out a VM object and its shadow chain
3175 usage: showvmobject <vm_object> [-S] [-P]
3176 -S: show VM object shadow chain
3177 -P: show pager info (mapped file, compressed pages, ...)
3179 if cmd_args
== None or len(cmd_args
) < 1:
3180 print "Invalid argument.", ShowMapVME
.__doc
__
3182 show_pager_info
= False
3183 show_all_shadows
= False
3184 if "-P" in cmd_options
:
3185 show_pager_info
= True
3186 if "-S" in cmd_options
:
3187 show_all_shadows
= True
3188 object = kern
.GetValueFromAddress(cmd_args
[0], 'vm_object_t')
3189 showvmobject(object, 0, 0, show_pager_info
, show_all_shadows
)
3191 def showvmobject(object, offset
=0, size
=0, show_pager_info
=False, show_all_shadows
=False):
3192 page_size
= kern
.globals.page_size
3193 vnode_pager_ops
= kern
.globals.vnode_pager_ops
3194 vnode_pager_ops_addr
= unsigned(addressof(vnode_pager_ops
))
3196 if size
== 0 and object != 0 and object.internal
:
3197 size
= object.vo_un1
.vou_size
3200 if show_all_shadows
== False and depth
!= 1 and object.shadow
!= 0:
3201 offset
+= unsigned(object.vo_un2
.vou_shadow_offset
)
3202 object = object.shadow
3204 if object.copy_strategy
== 0:
3206 elif object.copy_strategy
== 2:
3208 elif object.copy_strategy
== 4:
3212 copy_strategy
=str(object.copy_strategy
)
3214 internal
= "internal"
3216 internal
= "external"
3217 purgeable
= "NVED"[int(object.purgable
)]
3219 if object.phys_contiguous
:
3220 pager_string
= pager_string
+ "phys_contig {:#018x}:{:#018x} ".format(unsigned(object.vo_un2
.vou_shadow_offset
), unsigned(object.vo_un1
.vou_size
))
3221 pager
= object.pager
3222 if show_pager_info
and pager
!= 0:
3224 pager_string
= pager_string
+ "-> compressed:{:d}".format(GetCompressedPagesForObject(object))
3225 elif unsigned(pager
.mo_pager_ops
) == vnode_pager_ops_addr
:
3226 vnode_pager
= Cast(pager
,'vnode_pager *')
3227 pager_string
= pager_string
+ "-> " + GetVnodePath(vnode_pager
.vnode_handle
)
3229 pager_string
= pager_string
+ "-> {:s}:{: <#018x}".format(pager
.mo_pager_ops
.memory_object_pager_name
, pager
)
3230 print "{:>18d} {:#018x}:{:#018x} {: <#018x} ref:{:<6d} ts:{:1d} strat:{:1s} purg:{:1s} {:s} wtag:{:d} ({:d} {:d} {:d}) {:s}".format(depth
,offset
,offset
+size
,object,object.ref_count
,object.true_share
,copy_strategy
,purgeable
,internal
,object.wire_tag
,unsigned(object.vo_un1
.vou_size
)/page_size
,object.resident_page_count
,object.wired_page_count
,pager_string
)
3231 # print " #{:<5d} obj {: <#018x} ref:{:<6d} ts:{:1d} strat:{:1s} {:s} size:{:<10d} wired:{:<10d} resident:{:<10d} reusable:{:<10d}".format(depth,object,object.ref_count,object.true_share,copy_strategy,internal,object.vo_un1.vou_size/page_size,object.wired_page_count,object.resident_page_count,object.reusable_page_count)
3232 offset
+= unsigned(object.vo_un2
.vou_shadow_offset
)
3233 object = object.shadow
3235 def showmapvme(map, start_vaddr
, end_vaddr
, show_pager_info
, show_all_shadows
, reverse_order
=False, show_rb_tree
=False):
3238 rsize
= int(map.pmap
.stats
.resident_count
)
3239 print "{:<18s} {:<18s} {:<18s} {:>10s} {:>18s} {:>18s}:{:<18s} {:<7s}".format("vm_map","pmap","size","#ents","rsize","start","end","pgshift")
3240 print "{: <#018x} {: <#018x} {:#018x} {:>10d} {:>18d} {:#018x}:{:#018x} {:>7d}".format(map,map.pmap
,unsigned(map.size
),map.hdr
.nentries
,rsize
,map.hdr
.links
.start
,map.hdr
.links
.end
,map.hdr
.page_shift
)
3241 showmaphdrvme(map.hdr
, map.pmap
, start_vaddr
, end_vaddr
, show_pager_info
, show_all_shadows
, reverse_order
, show_rb_tree
)
3243 def showmapcopyvme(mapcopy
, start_vaddr
=0, end_vaddr
=0, show_pager_info
=True, show_all_shadows
=True, reverse_order
=False, show_rb_tree
=False):
3244 print "{:<18s} {:<18s} {:<18s} {:>10s} {:>18s} {:>18s}:{:<18s} {:<7s}".format("vm_map_copy","offset","size","#ents","rsize","start","end","pgshift")
3245 print "{: <#018x} {:#018x} {:#018x} {:>10d} {:>18d} {:#018x}:{:#018x} {:>7d}".format(mapcopy
,mapcopy
.offset
,mapcopy
.size
,mapcopy
.c_u
.hdr
.nentries
,0,mapcopy
.c_u
.hdr
.links
.start
,mapcopy
.c_u
.hdr
.links
.end
,mapcopy
.c_u
.hdr
.page_shift
)
3246 showmaphdrvme(mapcopy
.c_u
.hdr
, 0, start_vaddr
, end_vaddr
, show_pager_info
, show_all_shadows
, reverse_order
, show_rb_tree
)
3248 def showmaphdrvme(maphdr
, pmap
, start_vaddr
, end_vaddr
, show_pager_info
, show_all_shadows
, reverse_order
, show_rb_tree
):
3249 page_size
= kern
.globals.page_size
3250 vnode_pager_ops
= kern
.globals.vnode_pager_ops
3251 vnode_pager_ops_addr
= unsigned(addressof(vnode_pager_ops
))
3252 if hasattr(kern
.globals, 'compressor_object'):
3253 compressor_object
= kern
.globals.compressor_object
3255 compressor_object
= -1;
3256 vme_list_head
= maphdr
.links
3257 vme_ptr_type
= GetType('vm_map_entry *')
3258 print "{:<18s} {:>18s}:{:<18s} {:>10s} {:<8s} {:<16s} {:<18s} {:<18s}".format("entry","start","end","#pgs","tag.kmod","prot&flags","object","offset")
3259 last_end
= unsigned(maphdr
.links
.start
)
3261 for vme
in IterateQueue(vme_list_head
, vme_ptr_type
, "links", reverse_order
):
3262 if start_vaddr
!= 0 and end_vaddr
!= 0:
3263 if unsigned(vme
.links
.start
) > end_vaddr
:
3265 if unsigned(vme
.links
.end
) <= start_vaddr
:
3266 last_end
= unsigned(vme
.links
.end
)
3267 skipped_entries
= skipped_entries
+ 1
3269 if skipped_entries
!= 0:
3270 print "... skipped {:d} entries ...".format(skipped_entries
)
3272 if unsigned(vme
.links
.start
) != last_end
:
3273 print "{:18s} {:#018x}:{:#018x} {:>10d}".format("------------------",last_end
,vme
.links
.start
,(unsigned(vme
.links
.start
) - last_end
)/page_size
)
3274 last_end
= unsigned(vme
.links
.end
)
3275 size
= unsigned(vme
.links
.end
) - unsigned(vme
.links
.start
)
3276 object = vme
.vme_object
.vmo_object
3278 object_str
= "{: <#018x}".format(object)
3279 elif vme
.is_sub_map
:
3280 if object == kern
.globals.bufferhdr_map
:
3281 object_str
= "BUFFERHDR_MAP"
3282 elif object == kern
.globals.mb_map
:
3283 object_str
= "MB_MAP"
3284 elif object == kern
.globals.bsd_pageable_map
:
3285 object_str
= "BSD_PAGEABLE_MAP"
3286 elif object == kern
.globals.ipc_kernel_map
:
3287 object_str
= "IPC_KERNEL_MAP"
3288 elif object == kern
.globals.ipc_kernel_copy_map
:
3289 object_str
= "IPC_KERNEL_COPY_MAP"
3290 elif object == kern
.globals.kalloc_map
:
3291 object_str
= "KALLOC_MAP"
3292 elif hasattr(kern
.globals, 'compressor_map') and object == kern
.globals.compressor_map
:
3293 object_str
= "COMPRESSOR_MAP"
3294 elif hasattr(kern
.globals, 'gzalloc_map') and object == kern
.globals.gzalloc_map
:
3295 object_str
= "GZALLOC_MAP"
3296 elif hasattr(kern
.globals, 'g_kext_map') and object == kern
.globals.g_kext_map
:
3297 object_str
= "G_KEXT_MAP"
3298 elif hasattr(kern
.globals, 'vector_upl_submap') and object == kern
.globals.vector_upl_submap
:
3299 object_str
= "VECTOR_UPL_SUBMAP"
3301 object_str
= "submap:{: <#018x}".format(object)
3303 if object == kern
.globals.kernel_object
:
3304 object_str
= "KERNEL_OBJECT"
3305 elif object == kern
.globals.vm_submap_object
:
3306 object_str
= "VM_SUBMAP_OBJECT"
3307 elif object == compressor_object
:
3308 object_str
= "COMPRESSOR_OBJECT"
3310 object_str
= "{: <#018x}".format(object)
3311 offset
= unsigned(vme
.vme_offset
) & ~
0xFFF
3312 tag
= unsigned(vme
.vme_offset
& 0xFFF)
3314 if vme
.protection
& 0x1:
3318 if vme
.protection
& 0x2:
3322 if vme
.protection
& 0x4:
3327 if vme
.max_protection
& 0x1:
3328 max_protection
+="r"
3330 max_protection
+= "-"
3331 if vme
.max_protection
& 0x2:
3332 max_protection
+= "w"
3334 max_protection
+= "-"
3335 if vme
.max_protection
& 0x4:
3336 max_protection
+= "x"
3338 max_protection
+= "-"
3348 if vme
.used_for_jit
:
3351 if pmap
== kern
.globals.kernel_pmap
:
3352 xsite
= Cast(kern
.globals.vm_allocation_sites
[tag
],'OSKextAccount *')
3353 if xsite
and xsite
.site
.flags
& 0x0200:
3354 tagstr
= ".{:<3d}".format(xsite
.loadTag
)
3357 rb_info
= "l={: <#018x} r={: <#018x} p={: <#018x}".format(vme
.store
.entry
.rbe_left
, vme
.store
.entry
.rbe_right
, vme
.store
.entry
.rbe_parent
)
3358 print "{: <#018x} {:#018x}:{:#018x} {:>10d} {:>3d}{:<4s} {:3s}/{:3s}/{:<8s} {:<18s} {:<#18x} {:s}".format(vme
,vme
.links
.start
,vme
.links
.end
,(unsigned(vme
.links
.end
)-unsigned(vme
.links
.start
))/page_size
,tag
,tagstr
,protection
,max_protection
,vme_flags
,object_str
,offset
, rb_info
)
3359 if (show_pager_info
or show_all_shadows
) and vme
.is_sub_map
== 0 and vme
.vme_object
.vmo_object
!= 0:
3360 object = vme
.vme_object
.vmo_object
3363 showvmobject(object, offset
, size
, show_pager_info
, show_all_shadows
)
3364 if start_vaddr
!= 0 or end_vaddr
!= 0:
3366 elif unsigned(maphdr
.links
.end
) > last_end
:
3367 print "{:18s} {:#018x}:{:#018x} {:>10d}".format("------------------",last_end
,maphdr
.links
.end
,(unsigned(maphdr
.links
.end
) - last_end
)/page_size
)
3370 def CountMapTags(map, tagcounts
, slow
):
3371 page_size
= unsigned(kern
.globals.page_size
)
3372 vme_list_head
= map.hdr
.links
3373 vme_ptr_type
= GetType('vm_map_entry *')
3374 for vme
in IterateQueue(vme_list_head
, vme_ptr_type
, "links"):
3375 object = vme
.vme_object
.vmo_object
3376 tag
= vme
.vme_offset
& 0xFFF
3377 if object == kern
.globals.kernel_object
:
3380 count
= unsigned(vme
.links
.end
- vme
.links
.start
) / page_size
3382 addr
= unsigned(vme
.links
.start
)
3383 while addr
< unsigned(vme
.links
.end
):
3384 hash_id
= _calc_vm_page_hash(object, addr
)
3385 page_list
= kern
.globals.vm_page_buckets
[hash_id
].page_list
3386 page
= _vm_page_unpack_ptr(page_list
)
3388 vmpage
= kern
.GetValueFromAddress(page
, 'vm_page_t')
3389 if (addr
== unsigned(vmpage
.vmp_offset
)) and (object == vm_object_t(_vm_page_unpack_ptr(vmpage
.vmp_object
))):
3390 if (not vmpage
.vmp_local
) and (vmpage
.vmp_wire_count
> 0):
3393 page
= _vm_page_unpack_ptr(vmpage
.vmp_next_m
)
3395 tagcounts
[tag
] += count
3396 elif vme
.is_sub_map
:
3397 CountMapTags(Cast(object,'vm_map_t'), tagcounts
, slow
)
3400 def CountWiredObject(object, tagcounts
):
3401 tagcounts
[unsigned(object.wire_tag
)] += object.wired_page_count
3404 def GetKmodIDName(kmod_id
):
3405 kmod_val
= kern
.globals.kmod
3406 for kmod
in IterateLinkedList(kmod_val
, 'next'):
3407 if (kmod
.id == kmod_id
):
3408 return "{:<50s}".format(kmod
.name
)
3412 0: "VM_KERN_MEMORY_NONE",
3413 1: "VM_KERN_MEMORY_OSFMK",
3414 2: "VM_KERN_MEMORY_BSD",
3415 3: "VM_KERN_MEMORY_IOKIT",
3416 4: "VM_KERN_MEMORY_LIBKERN",
3417 5: "VM_KERN_MEMORY_OSKEXT",
3418 6: "VM_KERN_MEMORY_KEXT",
3419 7: "VM_KERN_MEMORY_IPC",
3420 8: "VM_KERN_MEMORY_STACK",
3421 9: "VM_KERN_MEMORY_CPU",
3422 10: "VM_KERN_MEMORY_PMAP",
3423 11: "VM_KERN_MEMORY_PTE",
3424 12: "VM_KERN_MEMORY_ZONE",
3425 13: "VM_KERN_MEMORY_KALLOC",
3426 14: "VM_KERN_MEMORY_COMPRESSOR",
3427 15: "VM_KERN_MEMORY_COMPRESSED_DATA",
3428 16: "VM_KERN_MEMORY_PHANTOM_CACHE",
3429 17: "VM_KERN_MEMORY_WAITQ",
3430 18: "VM_KERN_MEMORY_DIAG",
3431 19: "VM_KERN_MEMORY_LOG",
3432 20: "VM_KERN_MEMORY_FILE",
3433 21: "VM_KERN_MEMORY_MBUF",
3434 22: "VM_KERN_MEMORY_UBC",
3435 23: "VM_KERN_MEMORY_SECURITY",
3436 24: "VM_KERN_MEMORY_MLOCK",
3437 25: "VM_KERN_MEMORY_REASON",
3438 26: "VM_KERN_MEMORY_SKYWALK",
3439 27: "VM_KERN_MEMORY_LTABLE",
3440 28: "VM_KERN_MEMORY_HV",
3441 255:"VM_KERN_MEMORY_ANY",
3444 def GetVMKernName(tag
):
3445 """ returns the formatted name for a vmtag and
3446 the sub-tag for kmod tags.
3448 if ((tag
<= 27) or (tag
== 255)):
3449 return (FixedTags
[tag
], "")
3450 site
= kern
.globals.vm_allocation_sites
[tag
]
3452 if site
.flags
& 0x007F:
3453 cstr
= addressof(site
.subtotals
[site
.subtotalscount
])
3454 return ("{:<50s}".format(str(Cast(cstr
, 'char *'))), "")
3456 if site
.flags
& 0x0200:
3457 xsite
= Cast(site
,'OSKextAccount *')
3458 tagstr
= ".{:<3d}".format(xsite
.loadTag
)
3459 return (GetKmodIDName(xsite
.loadTag
), tagstr
);
3461 return (kern
.Symbolicate(site
), "")
3464 @lldb_command("showvmtags", "ASJ")
3465 def showvmtags(cmd_args
=None, cmd_options
={}):
3466 """Routine to print out info about kernel wired page allocations
3468 iterates kernel map and vm objects totaling allocations by tag.
3469 usage: showvmtags -S
3470 also iterates kernel object pages individually - slow.
3471 usage: showvmtags -A
3472 show all tags, even tags that have no wired count
3473 usage: showvmtags -J
3478 if "-S" in cmd_options
:
3481 if "-A" in cmd_options
:
3483 if "-J" in cmd_options
:
3486 page_size
= unsigned(kern
.globals.page_size
)
3487 nsites
= unsigned(kern
.globals.vm_allocation_tag_highest
) + 1
3488 tagcounts
= [0] * nsites
3489 tagpeaks
= [0] * nsites
3490 tagmapped
= [0] * nsites
3492 if kern
.globals.vm_tag_active_update
:
3493 for tag
in range(nsites
):
3494 site
= kern
.globals.vm_allocation_sites
[tag
]
3496 tagcounts
[tag
] = unsigned(site
.total
)
3497 tagmapped
[tag
] = unsigned(site
.mapped
)
3498 tagpeaks
[tag
] = unsigned(site
.peak
)
3500 queue_head
= kern
.globals.vm_objects_wired
3501 for object in IterateQueue(queue_head
, 'struct vm_object *', 'wired_objq'):
3502 if object != kern
.globals.kernel_object
:
3503 CountWiredObject(object, tagcounts
)
3505 CountMapTags(kern
.globals.kernel_map
, tagcounts
, slow
)
3510 for tag
in range(nsites
):
3511 if all_tags
or tagcounts
[tag
] or tagmapped
[tag
]:
3513 total
+= tagcounts
[tag
]
3514 totalmapped
+= tagmapped
[tag
]
3515 (sitestr
, tagstr
) = GetVMKernName(tag
)
3516 current
["name"] = sitestr
3517 current
["size"] = tagcounts
[tag
]
3518 current
["mapped"] = tagmapped
[tag
]
3519 current
["peak"] = tagpeaks
[tag
]
3520 current
["tag"] = tag
3521 current
["tagstr"] = tagstr
3522 current
["subtotals"] = []
3524 site
= kern
.globals.vm_allocation_sites
[tag
]
3525 for sub
in range(site
.subtotalscount
):
3526 alloctag
= unsigned(site
.subtotals
[sub
].tag
)
3527 amount
= unsigned(site
.subtotals
[sub
].total
)
3528 subsite
= kern
.globals.vm_allocation_sites
[alloctag
]
3529 if alloctag
and subsite
:
3530 (sitestr
, tagstr
) = GetVMKernName(alloctag
)
3531 current
["subtotals"].append({
3533 "flags": int(subsite
.flags
),
3538 tags
.append(current
)
3541 print json
.dumps(tags
)
3543 print " vm_allocation_tag_highest: {:<7d} ".format(nsites
- 1)
3544 print " {:<7s} {:>7s} {:>7s} {:>7s} {:<50s}".format("tag.kmod", "peak", "size", "mapped", "name")
3548 print " {:>3d}{:<4s} {:>7d}K {:>7d}K {:>7d}K {:<50s}".format(tag
["tag"], tag
["tagstr"], tag
["peak"] / 1024, tag
["size"] / 1024, tag
["mapped"] / 1024, tag
["name"])
3549 for sub
in tag
["subtotals"]:
3550 if ((sub
["flags"] & 0x007f) == 0):
3555 print " {:>7s} {:>7s} {:>7s} {:>7d}K {:s} {:>3d}{:<4s} {:<50s}".format(" ", " ", " ", sub
["amount"] / 1024, kind_str
, sub
["tag"], sub
["tagstr"], sub
["sitestr"])
3557 print "Total: {:>7d}K {:>7d}K".format(total
/ 1024, totalmapped
/ 1024)
3561 def FindVMEntriesForVnode(task
, vn
):
3562 """ returns an array of vme that have the vnode set to defined vnode
3563 each entry in array is of format (vme, start_addr, end_address, protection)
3568 pager_ops_addr
= unsigned(addressof(kern
.globals.vnode_pager_ops
))
3569 debuglog("pager_ops_addr %s" % hex(pager_ops_addr
))
3571 if unsigned(pmap
) == 0:
3573 vme_list_head
= vmmap
.hdr
.links
3574 vme_ptr_type
= gettype('vm_map_entry *')
3575 for vme
in IterateQueue(vme_list_head
, vme_ptr_type
, 'links'):
3577 if unsigned(vme
.is_sub_map
) == 0 and unsigned(vme
.vme_object
.vmo_object
) != 0:
3578 obj
= vme
.vme_object
.vmo_object
3587 vn_pager
= Cast(obj
.pager
, 'vnode_pager *')
3588 if unsigned(vn_pager
.vn_pgr_hdr
.mo_pager_ops
) == pager_ops_addr
and unsigned(vn_pager
.vnode_handle
) == unsigned(vn
):
3589 retval
.append((vme
, unsigned(vme
.links
.start
), unsigned(vme
.links
.end
), unsigned(vme
.protection
)))
3593 @lldb_command('showtaskloadinfo')
3594 def ShowTaskLoadInfo(cmd_args
=None, cmd_options
={}):
3595 """ Print the load address and uuid for the process
3596 Usage: (lldb)showtaskloadinfo <task_t>
3599 raise ArgumentError("Insufficient arguments")
3600 t
= kern
.GetValueFromAddress(cmd_args
[0], 'struct task *')
3601 print_format
= "0x{0:x} - 0x{1:x} {2: <50s} (??? - ???) <{3: <36s}> {4: <50s}"
3602 p
= Cast(t
.bsd_info
, 'struct proc *')
3604 uuid_out_string
= "{a[0]:02X}{a[1]:02X}{a[2]:02X}{a[3]:02X}-{a[4]:02X}{a[5]:02X}-{a[6]:02X}{a[7]:02X}-{a[8]:02X}{a[9]:02X}-{a[10]:02X}{a[11]:02X}{a[12]:02X}{a[13]:02X}{a[14]:02X}{a[15]:02X}".format(a
=uuid
)
3605 filepath
= GetVnodePath(p
.p_textvp
)
3606 libname
= filepath
.split('/')[-1]
3607 #print "uuid: %s file: %s" % (uuid_out_string, filepath)
3608 mappings
= FindVMEntriesForVnode(t
, p
.p_textvp
)
3615 #print "Load address: %s" % hex(m[1])
3616 print print_format
.format(load_addr
, end_addr
, libname
, uuid_out_string
, filepath
)
3619 @header("{0: <20s} {1: <20s} {2: <20s}".format("vm_page_t", "offset", "object"))
3620 @lldb_command('vmpagelookup')
3621 def VMPageLookup(cmd_args
=None):
3622 """ Print the pages in the page bucket corresponding to the provided object and offset.
3623 Usage: (lldb)vmpagelookup <vm_object_t> <vm_offset_t>
3625 if cmd_args
== None or len(cmd_args
) < 2:
3626 raise ArgumentError("Please specify an object and offset.")
3627 format_string
= "{0: <#020x} {1: <#020x} {2: <#020x}\n"
3629 obj
= kern
.GetValueFromAddress(cmd_args
[0],'unsigned long long')
3630 off
= kern
.GetValueFromAddress(cmd_args
[1],'unsigned long long')
3632 hash_id
= _calc_vm_page_hash(obj
, off
)
3634 page_list
= kern
.globals.vm_page_buckets
[hash_id
].page_list
3635 print("hash_id: 0x%x page_list: 0x%x\n" % (unsigned(hash_id
), unsigned(page_list
)))
3637 print VMPageLookup
.header
3638 page
= _vm_page_unpack_ptr(page_list
)
3640 pg_t
= kern
.GetValueFromAddress(page
, 'vm_page_t')
3641 print format_string
.format(page
, pg_t
.vmp_offset
, _vm_page_unpack_ptr(pg_t
.vmp_object
))
3642 page
= _vm_page_unpack_ptr(pg_t
.vmp_next_m
)
3646 @lldb_command('vmpage_get_phys_page')
3647 def VmPageGetPhysPage(cmd_args
=None):
3648 """ return the physical page for a vm_page_t
3649 usage: vm_page_get_phys_page <vm_page_t>
3651 if cmd_args
== None or len(cmd_args
) < 1:
3652 print "Please provide valid vm_page_t. Type help vm_page_get_phys_page for help."
3655 page
= kern
.GetValueFromAddress(cmd_args
[0], 'vm_page_t')
3656 phys_page
= _vm_page_get_phys_page(page
)
3657 print("phys_page = 0x%x\n" % phys_page
)
3660 def _vm_page_get_phys_page(page
):
3661 if kern
.arch
== 'x86_64':
3662 return page
.vmp_phys_page
3668 if m
>= unsigned(kern
.globals.vm_page_array_beginning_addr
) and m
< unsigned(kern
.globals.vm_page_array_ending_addr
) :
3669 return (m
- unsigned(kern
.globals.vm_page_array_beginning_addr
)) / sizeof('struct vm_page') + unsigned(kern
.globals.vm_first_phys_ppnum
)
3671 page_with_ppnum
= Cast(page
, 'uint32_t *')
3672 ppnum_offset
= sizeof('struct vm_page') / sizeof('uint32_t')
3673 return page_with_ppnum
[ppnum_offset
]
3676 @lldb_command('vmpage_unpack_ptr')
3677 def VmPageUnpackPtr(cmd_args
=None):
3678 """ unpack a pointer
3679 usage: vm_page_unpack_ptr <packed_ptr>
3681 if cmd_args
== None or len(cmd_args
) < 1:
3682 print "Please provide valid packed pointer argument. Type help vm_page_unpack_ptr for help."
3685 packed
= kern
.GetValueFromAddress(cmd_args
[0],'unsigned long')
3686 unpacked
= _vm_page_unpack_ptr(packed
)
3687 print("unpacked pointer = 0x%x\n" % unpacked
)
3690 def _vm_page_unpack_ptr(page
):
3691 if kern
.ptrsize
== 4 :
3697 params
= kern
.globals.vm_page_packing_params
3698 ptr_shift
= params
.vmpp_shift
3699 ptr_mask
= kern
.globals.vm_packed_from_vm_pages_array_mask
3701 # when no mask and shift on 64bit systems, we're working with real/non-packed pointers
3702 if ptr_shift
== 0 and ptr_mask
== 0:
3705 if unsigned(page
) & unsigned(ptr_mask
):
3706 masked_page
= (unsigned(page
) & ~ptr_mask
)
3707 # can't use addressof(kern.globals.vm_pages[masked_page]) due to 32 bit limitation in SB bridge
3708 vm_pages_addr
= unsigned(addressof(kern
.globals.vm_pages
[0]))
3709 element_size
= unsigned(addressof(kern
.globals.vm_pages
[1])) - vm_pages_addr
3710 return (vm_pages_addr
+ masked_page
* element_size
)
3711 return vm_unpack_pointer(page
, params
)
3713 @lldb_command('calcvmpagehash')
3714 def CalcVMPageHash(cmd_args
=None):
3715 """ Get the page bucket corresponding to the provided object and offset.
3716 Usage: (lldb)calcvmpagehash <vm_object_t> <vm_offset_t>
3718 if cmd_args
== None or len(cmd_args
) < 2:
3719 raise ArgumentError("Please specify an object and offset.")
3721 obj
= kern
.GetValueFromAddress(cmd_args
[0],'unsigned long long')
3722 off
= kern
.GetValueFromAddress(cmd_args
[1],'unsigned long long')
3724 hash_id
= _calc_vm_page_hash(obj
, off
)
3726 print("hash_id: 0x%x page_list: 0x%x\n" % (unsigned(hash_id
), unsigned(kern
.globals.vm_page_buckets
[hash_id
].page_list
)))
3729 def _calc_vm_page_hash(obj
, off
):
3730 bucket_hash
= (int) (kern
.globals.vm_page_bucket_hash
)
3731 hash_mask
= (int) (kern
.globals.vm_page_hash_mask
)
3733 one
= (obj
* bucket_hash
) & 0xFFFFFFFF
3734 two
= off
>> unsigned(kern
.globals.page_shift
)
3735 three
= two ^ bucket_hash
3737 hash_id
= four
& hash_mask
3741 #Macro: showallocatedzoneelement
3742 @lldb_command('showallocatedzoneelement')
3743 def ShowAllocatedElementsInZone(cmd_args
=None, cmd_options
={}):
3744 """ Show all the allocated elements in a zone
3745 usage: showzoneallocelements <address of zone>
3747 if len(cmd_args
) < 1:
3748 raise ArgumentError("Please specify a zone")
3750 zone
= kern
.GetValueFromAddress(cmd_args
[0], 'struct zone *')
3751 elements
= FindAllocatedElementsInZone(zone
)
3753 for elem
in elements
:
3754 print "{0: >10d}/{1:<10d} element: {2: <#20x}".format(i
, len(elements
), elem
)
3757 #EndMacro: showallocatedzoneelement
3759 def FindAllocatedElementsInZone(zone
):
3762 if not zone
.z_self
or zone
.permanent
:
3765 for head
in [zone
.pages_any_free_foreign
, zone
.pages_all_used_foreign
,
3766 zone
.pages_intermediate
, zone
.pages_all_used
]:
3768 for meta
in ZoneIteratePageQueue(head
):
3769 free_elements
= set(meta
.iterateFreeList())
3771 for elem
in meta
.iterateElements():
3772 if elem
in free_elements
:
3775 if elem
not in free_elements
:
3776 elements
.append(elem
)
3777 elem
+= zone
.z_elem_size
3781 def match_vm_page_attributes(page
, matching_attributes
):
3782 page_ptr
= addressof(page
)
3783 unpacked_vm_object
= _vm_page_unpack_ptr(page
.vmp_object
)
3784 matched_attributes
= 0
3785 if "vmp_q_state" in matching_attributes
and (page
.vmp_q_state
== matching_attributes
["vmp_q_state"]):
3786 matched_attributes
+= 1
3787 if "vm_object" in matching_attributes
and (unsigned(unpacked_vm_object
) == unsigned(matching_attributes
["vm_object"])):
3788 matched_attributes
+= 1
3789 if "vmp_offset" in matching_attributes
and (unsigned(page
.vmp_offset
) == unsigned(matching_attributes
["vmp_offset"])):
3790 matched_attributes
+= 1
3791 if "phys_page" in matching_attributes
and (unsigned(_vm_page_get_phys_page(page_ptr
)) == unsigned(matching_attributes
["phys_page"])):
3792 matched_attributes
+= 1
3793 if "bitfield" in matching_attributes
and unsigned(page
.__getattr
__(matching_attributes
["bitfield"])) == 1:
3794 matched_attributes
+= 1
3796 return matched_attributes
3798 #Macro scan_vm_pages
3799 @header("{0: >26s}{1: >20s}{2: >10s}{3: >20s}{4: >20s}{5: >16s}".format("vm_pages_index/zone", "vm_page", "q_state", "vm_object", "offset", "ppn", "bitfield", "from_zone_map"))
3800 @lldb_command('scan_vm_pages', 'S:O:F:I:P:B:I:N:ZA')
3801 def ScanVMPages(cmd_args
=None, cmd_options
={}):
3802 """ Scan the global vm_pages array (-A) and/or vmpages zone (-Z) for pages with matching attributes.
3803 usage: scan_vm_pages <matching attribute(s)> [-A start vm_pages index] [-N number of pages to scan] [-Z scan vm_pages zone]
3805 scan_vm_pages -A: scan vm pages in the global vm_pages array
3806 scan_vm_pages -Z: scan vm pages allocated from the vm.pages zone
3807 scan_vm_pages <-A/-Z> -S <vm_page_q_state value>: Find vm pages in the specified queue
3808 scan_vm_pages <-A/-Z> -O <vm_object>: Find vm pages in the specified vm_object
3809 scan_vm_pages <-A/-Z> -F <offset>: Find vm pages with the specified vmp_offset value
3810 scan_vm_pages <-A/-Z> -P <phys_page>: Find vm pages with the specified physical page number
3811 scan_vm_pages <-A/-Z> -B <bitfield>: Find vm pages with the bitfield set
3812 scan_vm_pages <-A> -I <start_index>: Start the scan from start_index
3813 scan_vm_pages <-A> -N <npages>: Scan at most npages
3815 if (len(cmd_options
) < 1):
3816 raise ArgumentError("Please specify at least one matching attribute")
3818 vm_pages
= kern
.globals.vm_pages
3819 vm_pages_count
= kern
.globals.vm_pages_count
3822 npages
= vm_pages_count
3823 scan_vmpages_array
= False
3824 scan_vmpages_zone
= False
3827 if "-A" in cmd_options
:
3828 scan_vmpages_array
= True
3830 if "-Z" in cmd_options
:
3831 scan_vmpages_zone
= True
3833 if scan_vmpages_array
== False and scan_vmpages_zone
== False:
3834 raise ArgumentError("Please specify where to scan (-A: vm_pages array, -Z: vm.pages zone)")
3836 attribute_values
= {}
3837 if "-S" in cmd_options
:
3838 attribute_values
["vmp_q_state"] = kern
.GetValueFromAddress(cmd_options
["-S"], 'int')
3839 attribute_count
+= 1
3841 if "-O" in cmd_options
:
3842 attribute_values
["vm_object"] = kern
.GetValueFromAddress(cmd_options
["-O"], 'vm_object_t')
3843 attribute_count
+= 1
3845 if "-F" in cmd_options
:
3846 attribute_values
["vmp_offset"] = kern
.GetValueFromAddress(cmd_options
["-F"], 'unsigned long long')
3847 attribute_count
+= 1
3849 if "-P" in cmd_options
:
3850 attribute_values
["phys_page"] = kern
.GetValueFromAddress(cmd_options
["-P"], 'unsigned int')
3851 attribute_count
+= 1
3853 if "-B" in cmd_options
:
3854 valid_vmp_bitfields
= [
3855 "vmp_in_background",
3856 "vmp_on_backgroundq",
3870 "vmp_free_when_done",
3884 "vmp_written_by_kernel",
3885 "vmp_unused_object_bits"
3887 attribute_values
["bitfield"] = cmd_options
["-B"]
3888 if attribute_values
["bitfield"] in valid_vmp_bitfields
:
3889 attribute_count
+= 1
3891 raise ArgumentError("Unknown bitfield: {0:>20s}".format(bitfield
))
3893 if "-I" in cmd_options
:
3894 start_index
= kern
.GetValueFromAddress(cmd_options
["-I"], 'int')
3895 npages
= vm_pages_count
- start_index
3897 if "-N" in cmd_options
:
3898 npages
= kern
.GetValueFromAddress(cmd_options
["-N"], 'int')
3900 raise ArgumentError("You specified -N 0, nothing to be scanned")
3902 end_index
= start_index
+ npages
- 1
3903 if end_index
>= vm_pages_count
:
3904 raise ArgumentError("Index range out of bound. vm_pages_count: {0:d}".format(vm_pages_count
))
3906 header_after_n_lines
= 40
3907 format_string
= "{0: >26s}{1: >#20x}{2: >10d}{3: >#20x}{4: >#20x}{5: >#16x}"
3910 if scan_vmpages_array
:
3911 print "Scanning vm_pages[{0:d} to {1:d}] for {2:d} matching attribute(s)......".format(start_index
, end_index
, attribute_count
)
3913 while i
<= end_index
:
3915 if match_vm_page_attributes(page
, attribute_values
) == attribute_count
:
3916 if found_in_array
% header_after_n_lines
== 0:
3917 print ScanVMPages
.header
3919 print format_string
.format(str(i
), addressof(page
), page
.vmp_q_state
, _vm_page_unpack_ptr(page
.vmp_object
), page
.vmp_offset
, _vm_page_get_phys_page(addressof(page
)))
3925 if scan_vmpages_zone
:
3926 page_size
= kern
.GetGlobalVariable('page_size')
3927 num_zones
= kern
.GetGlobalVariable('num_zones')
3928 zone_array
= kern
.GetGlobalVariable('zone_array')
3929 print "Scanning vm.pages zone for {0:d} matching attribute(s)......".format(attribute_count
)
3931 while i
< num_zones
:
3932 zone
= zone_array
[i
]
3933 if str(zone
.z_name
) == "vm pages":
3938 print "Cannot find vm_pages zone, skip the scan"
3940 print "Scanning page queues in the vm_pages zone..."
3941 elements
= FindAllocatedElementsInZone(zone
)
3942 for elem
in elements
:
3943 page
= kern
.GetValueFromAddress(elem
, 'vm_page_t')
3945 if match_vm_page_attributes(page
, attribute_values
) == attribute_count
:
3946 if found_in_zone
% header_after_n_lines
== 0:
3947 print ScanVMPages
.header
3949 vm_object
= _vm_page_unpack_ptr(page
.vmp_object
)
3950 phys_page
= _vm_page_get_phys_page(page
)
3951 print format_string
.format("vm_pages zone", elem
, page
.vmp_q_state
, vm_object
, page
.vmp_offset
, phys_page
)
3954 total
= found_in_array
+ found_in_zone
3955 print "Found {0:d} vm pages ({1:d} in array, {2:d} in zone) matching the requested {3:d} attribute(s)".format(total
, found_in_array
, found_in_zone
, attribute_count
)
3957 #EndMacro scan_vm_pages
3959 VM_PAGE_IS_WIRED
= 1
3961 @header("{0: <10s} of {1: <10s} {2: <20s} {3: <20s} {4: <20s} {5: <10s} {6: <5s}\t {7: <28s}\t{8: <50s}".format("index", "total", "vm_page_t", "offset", "next", "phys_page", "wire#", "first bitfield", "second bitfield"))
3962 @lldb_command('vmobjectwalkpages', 'CSBNQP:O:')
3963 def VMObjectWalkPages(cmd_args
=None, cmd_options
={}):
3964 """ Print the resident pages contained in the provided object. If a vm_page_t is provided as well, we
3965 specifically look for this page, highlighting it in the output or noting if it was not found. For
3966 each page, we confirm that it points to the object. We also keep track of the number of pages we
3967 see and compare this to the object's resident page count field.
3969 vmobjectwalkpages <vm_object_t> : Walk and print all the pages for a given object (up to 4K pages by default)
3970 vmobjectwalkpages <vm_object_t> -C : list pages in compressor after processing resident pages
3971 vmobjectwalkpages <vm_object_t> -B : Walk and print all the pages for a given object (up to 4K pages by default), traversing the memq backwards
3972 vmobjectwalkpages <vm_object_t> -N : Walk and print all the pages for a given object, ignore the page limit
3973 vmobjectwalkpages <vm_object_t> -Q : Walk all pages for a given object, looking for known signs of corruption (i.e. q_state == VM_PAGE_IS_WIRED && wire_count == 0)
3974 vmobjectwalkpages <vm_object_t> -P <vm_page_t> : Walk all the pages for a given object, annotate the specified page in the output with ***
3975 vmobjectwalkpages <vm_object_t> -P <vm_page_t> -S : Walk all the pages for a given object, stopping when we find the specified page
3976 vmobjectwalkpages <vm_object_t> -O <offset> : Like -P, but looks for given offset
3980 if (cmd_args
== None or len(cmd_args
) < 1):
3981 raise ArgumentError("Please specify at minimum a vm_object_t and optionally a vm_page_t")
3985 obj
= kern
.GetValueFromAddress(cmd_args
[0], 'vm_object_t')
3988 if "-P" in cmd_options
:
3989 page
= kern
.GetValueFromAddress(cmd_options
['-P'], 'vm_page_t')
3992 if "-O" in cmd_options
:
3993 off
= kern
.GetValueFromAddress(cmd_options
['-O'], 'vm_offset_t')
3996 if "-S" in cmd_options
:
3997 if page
== 0 and off
< 0:
3998 raise ArgumentError("-S can only be passed when a page is specified with -P or -O")
4001 walk_backwards
= False
4002 if "-B" in cmd_options
:
4003 walk_backwards
= True
4006 if "-Q" in cmd_options
:
4010 print VMObjectWalkPages
.header
4011 format_string
= "{0: <#10d} of {1: <#10d} {2: <#020x} {3: <#020x} {4: <#020x} {5: <#010x} {6: <#05d}\t"
4012 first_bitfield_format_string
= "{0: <#2d}:{1: <#1d}:{2: <#1d}:{3: <#1d}:{4: <#1d}:{5: <#1d}:{6: <#1d}:{7: <#1d}\t"
4013 second_bitfield_format_string
= "{0: <#1d}:{1: <#1d}:{2: <#1d}:{3: <#1d}:{4: <#1d}:{5: <#1d}:{6: <#1d}:"
4014 second_bitfield_format_string
+= "{7: <#1d}:{8: <#1d}:{9: <#1d}:{10: <#1d}:{11: <#1d}:{12: <#1d}:"
4015 second_bitfield_format_string
+= "{13: <#1d}:{14: <#1d}:{15: <#1d}:{16: <#1d}:{17: <#1d}:{18: <#1d}:{19: <#1d}:"
4016 second_bitfield_format_string
+= "{20: <#1d}:{21: <#1d}:{22: <#1d}:{23: <#1d}:{24: <#1d}:{25: <#1d}:{26: <#1d}\n"
4018 limit
= 4096 #arbitrary limit of number of pages to walk
4020 if "-N" in cmd_options
:
4024 if "-C" in cmd_options
:
4028 res_page_count
= unsigned(obj
.resident_page_count
)
4032 for vmp
in IterateQueue(obj
.memq
, "vm_page_t", "vmp_listq", walk_backwards
, unpack_ptr_fn
=_vm_page_unpack_ptr
):
4035 if (page
!= 0 and not(page_found
) and vmp
== page
):
4036 out_string
+= "******"
4039 if (off
> 0 and not(page_found
) and vmp
.vmp_offset
== off
):
4040 out_string
+= "******"
4043 if page
!= 0 or off
> 0 or quiet_mode
:
4044 if (page_count
% 1000) == 0:
4045 print "traversed %d pages ...\n" % (page_count
)
4047 out_string
+= format_string
.format(page_count
, res_page_count
, vmp
, vmp
.vmp_offset
, _vm_page_unpack_ptr(vmp
.vmp_listq
.next
), _vm_page_get_phys_page(vmp
), vmp
.vmp_wire_count
)
4048 out_string
+= first_bitfield_format_string
.format(vmp
.vmp_q_state
, vmp
.vmp_in_background
, vmp
.vmp_on_backgroundq
, vmp
.vmp_gobbled
, vmp
.vmp_laundry
, vmp
.vmp_no_cache
,
4049 vmp
.vmp_private
, vmp
.vmp_reference
)
4051 if hasattr(vmp
,'slid'):
4055 out_string
+= second_bitfield_format_string
.format(vmp
.vmp_busy
, vmp
.vmp_wanted
, vmp
.vmp_tabled
, vmp
.vmp_hashed
, vmp
.vmp_fictitious
, vmp
.vmp_clustered
,
4056 vmp
.vmp_pmapped
, vmp
.vmp_xpmapped
, vmp
.vmp_wpmapped
, vmp
.vmp_free_when_done
, vmp
.vmp_absent
,
4057 vmp
.vmp_error
, vmp
.vmp_dirty
, vmp
.vmp_cleaning
, vmp
.vmp_precious
, vmp
.vmp_overwriting
,
4058 vmp
.vmp_restart
, vmp
.vmp_unusual
, 0, 0,
4059 vmp
.vmp_cs_validated
, vmp
.vmp_cs_tainted
, vmp
.vmp_cs_nx
, vmp
.vmp_reusable
, vmp
.vmp_lopage
, vmp_slid
,
4060 vmp
.vmp_written_by_kernel
)
4062 if (vmp
in pages_seen
):
4063 print out_string
+ "cycle detected! we've seen vm_page_t: " + "{0: <#020x}".format(unsigned(vmp
)) + " twice. stopping...\n"
4066 if (_vm_page_unpack_ptr(vmp
.vmp_object
) != unsigned(obj
)):
4067 print out_string
+ " vm_page_t: " + "{0: <#020x}".format(unsigned(vmp
)) + " points to different vm_object_t: " + "{0: <#020x}".format(unsigned(_vm_page_unpack_ptr(vmp
.vmp_object
)))
4070 if (vmp
.vmp_q_state
== VM_PAGE_IS_WIRED
) and (vmp
.vmp_wire_count
== 0):
4071 print out_string
+ " page in wired state with wire_count of 0\n"
4072 print "vm_page_t: " + "{0: <#020x}".format(unsigned(vmp
)) + "\n"
4073 print "stopping...\n"
4076 if (hasattr(vmp
, 'vmp_unused_page_bits') and (vmp
.vmp_unused_page_bits
!= 0)):
4077 print out_string
+ " unused bits not zero for vm_page_t: " + "{0: <#020x}".format(unsigned(vmp
)) + " unused__pageq_bits: %d\n" % (vmp
.vmp_unused_page_bits
)
4078 print "stopping...\n"
4081 if (hasattr(vmp
, 'vmp_unused_object_bits') and (vmp
.vmp_unused_object_bits
!= 0)):
4082 print out_string
+ " unused bits not zero for vm_page_t: " + "{0: <#020x}".format(unsigned(vmp
)) + " unused_object_bits : %d\n" % (vmp
.vmp_unused_object_bits
)
4083 print "stopping...\n"
4089 hash_id
= _calc_vm_page_hash(obj
, vmp
.vmp_offset
)
4090 hash_page_list
= kern
.globals.vm_page_buckets
[hash_id
].page_list
4091 hash_page
= _vm_page_unpack_ptr(hash_page_list
)
4094 while (hash_page
!= 0):
4095 hash_page_t
= kern
.GetValueFromAddress(hash_page
, 'vm_page_t')
4096 if hash_page_t
== vmp
:
4098 hash_page
= _vm_page_unpack_ptr(hash_page_t
.vmp_next_m
)
4100 if (unsigned(vmp
) != unsigned(hash_page_t
)):
4101 print out_string
+ "unable to find page: " + "{0: <#020x}".format(unsigned(vmp
)) + " from object in kernel page bucket list\n"
4102 print lldb_run_command("vm_page_info %s 0x%x" % (cmd_args
[0], unsigned(vmp
.vmp_offset
)))
4105 if (page_count
>= limit
and not(ignore_limit
)):
4106 print out_string
+ "Limit reached (%d pages), stopping..." % (limit
)
4111 if page_found
and stop
:
4112 print("Object reports resident page count of: %d we stopped after traversing %d and finding the requested page.\n" % (unsigned(obj
.res_page_count
), unsigned(page_count
)))
4116 print("page found? : %s\n" % page_found
)
4119 print("page found? : %s\n" % page_found
)
4121 print("Object reports resident page count of %d, we saw %d pages when we walked the resident list.\n" % (unsigned(obj
.resident_page_count
), unsigned(page_count
)))
4123 if show_compressed
!= 0 and obj
.pager
!= 0 and unsigned(obj
.pager
.mo_pager_ops
) == unsigned(addressof(kern
.globals.compressor_pager_ops
)):
4124 pager
= Cast(obj
.pager
, 'compressor_pager *')
4125 chunks
= pager
.cpgr_num_slots
/ 128
4126 pagesize
= kern
.globals.page_size
4129 while page_idx
< pager
.cpgr_num_slots
:
4131 chunk
= pager
.cpgr_slots
.cpgr_islots
[page_idx
/ 128]
4132 slot
= chunk
[page_idx
% 128]
4133 elif pager
.cpgr_num_slots
> 2:
4134 slot
= pager
.cpgr_slots
.cpgr_dslots
[page_idx
]
4136 slot
= pager
.cpgr_slots
.cpgr_eslots
[page_idx
]
4139 print("compressed page for offset: %x slot %x\n" % ((page_idx
* pagesize
) - obj
.paging_offset
, slot
))
4140 page_idx
= page_idx
+ 1
4143 @lldb_command("show_all_apple_protect_pagers")
4144 def ShowAllAppleProtectPagers(cmd_args
=None):
4145 """Routine to print all apple_protect pagers
4146 usage: show_all_apple_protect_pagers
4148 print "{:>3s} {:<3s} {:<18s} {:>5s} {:>5s} {:>6s} {:<18s} {:<18s} {:<18s} {:<18s} {:<18s} {:<18s}\n".format("#", "#", "pager", "refs", "ready", "mapped", "mo_control", "object", "offset", "crypto_offset", "crypto_start", "crypto_end")
4149 qhead
= kern
.globals.apple_protect_pager_queue
4150 qtype
= GetType('apple_protect_pager *')
4151 qcnt
= kern
.globals.apple_protect_pager_count
4153 for pager
in IterateQueue(qhead
, qtype
, "pager_queue"):
4155 show_apple_protect_pager(pager
, qcnt
, idx
)
4157 @lldb_command("show_apple_protect_pager")
4158 def ShowAppleProtectPager(cmd_args
=None):
4159 """Routine to print out info about an apple_protect pager
4160 usage: show_apple_protect_pager <pager>
4162 if cmd_args
== None or len(cmd_args
) < 1:
4163 print "Invalid argument.", ShowAppleProtectPager
.__doc
__
4165 pager
= kern
.GetValueFromAddress(cmd_args
[0], 'apple_protect_pager_t')
4166 show_apple_protect_pager(pager
, 1, 1)
4168 def show_apple_protect_pager(pager
, qcnt
, idx
):
4169 object = pager
.backing_object
4170 shadow
= object.shadow
4173 shadow
= object.shadow
4174 vnode_pager
= Cast(object.pager
,'vnode_pager *')
4175 filename
= GetVnodePath(vnode_pager
.vnode_handle
)
4176 print "{:>3}/{:<3d} {: <#018x} {:>5d} {:>5d} {:>6d} {: <#018x} {: <#018x} {:#018x} {:#018x} {:#018x} {:#018x}\n\tcrypt_info:{: <#018x} <decrypt:{: <#018x} end:{:#018x} ops:{: <#018x} refs:{:<d}>\n\tvnode:{: <#018x} {:s}\n".format(idx
, qcnt
, pager
, pager
.ref_count
, pager
.is_ready
, pager
.is_mapped
, pager
.pager_control
, pager
.backing_object
, pager
.backing_offset
, pager
.crypto_backing_offset
, pager
.crypto_start
, pager
.crypto_end
, pager
.crypt_info
, pager
.crypt_info
.page_decrypt
, pager
.crypt_info
.crypt_end
, pager
.crypt_info
.crypt_ops
, pager
.crypt_info
.crypt_refcnt
, vnode_pager
.vnode_handle
, filename
)
4178 @lldb_command("show_console_ring")
4179 def ShowConsoleRingData(cmd_args
=None):
4180 """ Print console ring buffer stats and data
4182 cr
= kern
.globals.console_ring
4183 print "console_ring = {:#018x} buffer = {:#018x} length = {:<5d} used = {:<5d} read_ptr = {:#018x} write_ptr = {:#018x}".format(addressof(cr
), cr
.buffer, cr
.len, cr
.used
, cr
.read_ptr
, cr
.write_ptr
)
4185 for i
in range(unsigned(cr
.used
)):
4186 idx
= ((unsigned(cr
.read_ptr
) - unsigned(cr
.buffer)) + i
) % unsigned(cr
.len)
4187 pending_data
.append("{:c}".format(cr
.buffer[idx
]))
4191 print "".join(pending_data
)
4193 # Macro: showjetsamsnapshot
4195 @lldb_command("showjetsamsnapshot", "DA")
4196 def ShowJetsamSnapshot(cmd_args
=None, cmd_options
={}):
4197 """ Dump entries in the jetsam snapshot table
4198 usage: showjetsamsnapshot [-D] [-A]
4199 Use -D flag to print extra physfootprint details
4200 Use -A flag to print all entries (regardless of valid count)
4203 # Not shown are uuid, user_data, cpu_time
4207 show_footprint_details
= False
4208 show_all_entries
= False
4210 if "-D" in cmd_options
:
4211 show_footprint_details
= True
4213 if "-A" in cmd_options
:
4214 show_all_entries
= True
4216 valid_count
= kern
.globals.memorystatus_jetsam_snapshot_count
4217 max_count
= kern
.globals.memorystatus_jetsam_snapshot_max
4219 if (show_all_entries
== True):
4224 print "{:s}".format(valid_count
)
4225 print "{:s}".format(max_count
)
4228 print "The jetsam snapshot is empty."
4229 print "Use -A to force dump all entries (regardless of valid count)"
4232 # Dumps the snapshot header info
4233 print lldb_run_command('p *memorystatus_jetsam_snapshot')
4235 hdr_format
= "{0: >32s} {1: >5s} {2: >4s} {3: >6s} {4: >6s} {5: >20s} {6: >20s} {7: >20s} {8: >5s} {9: >10s} {10: >6s} {11: >6s} {12: >10s} {13: >15s} {14: >15s} {15: >15s}"
4236 if (show_footprint_details
== True):
4237 hdr_format
+= "{16: >15s} {17: >15s} {18: >12s} {19: >12s} {20: >17s} {21: >10s} {22: >13s} {23: >10s}"
4240 if (show_footprint_details
== False):
4241 print hdr_format
.format('command', 'index', 'pri', 'cid', 'pid', 'starttime', 'killtime', 'idletime', 'kill', '#ents', 'fds', 'gen', 'state', 'footprint', 'purgeable', 'lifetimeMax')
4242 print hdr_format
.format('', '', '', '', '', '(abs)', '(abs)', '(abs)', 'cause', '', '', 'Count', '', '(pages)', '(pages)', '(pages)')
4244 print hdr_format
.format('command', 'index', 'pri', 'cid', 'pid', 'starttime', 'killtime', 'idletime', 'kill', '#ents', 'fds', 'gen', 'state', 'footprint', 'purgeable', 'lifetimeMax', '|| internal', 'internal_comp', 'iokit_mapped', 'purge_nonvol', 'purge_nonvol_comp', 'alt_acct', 'alt_acct_comp', 'page_table')
4245 print hdr_format
.format('', '', '', '', '', '(abs)', '(abs)', '(abs)', 'cause', '', '', 'Count', '', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)')
4248 entry_format
= "{e.name: >32s} {index: >5d} {e.priority: >4d} {e.jse_coalition_jetsam_id: >6d} {e.pid: >6d} "\
4249 "{e.jse_starttime: >20d} {e.jse_killtime: >20d} "\
4250 "{e.jse_idle_delta: >20d} {e.killed: >5d} {e.jse_memory_region_count: >10d} "\
4251 "{e.fds: >6d} {e.jse_gencount: >6d} {e.state: >10x} {e.pages: >15d} "\
4252 "{e.purgeable_pages: >15d} {e.max_pages_lifetime: >15d}"
4254 if (show_footprint_details
== True):
4255 entry_format
+= "{e.jse_internal_pages: >15d} "\
4256 "{e.jse_internal_compressed_pages: >15d} "\
4257 "{e.jse_iokit_mapped_pages: >12d} "\
4258 "{e.jse_purgeable_nonvolatile_pages: >12d} "\
4259 "{e.jse_purgeable_nonvolatile_compressed_pages: >17d} "\
4260 "{e.jse_alternate_accounting_pages: >10d} "\
4261 "{e.jse_alternate_accounting_compressed_pages: >13d} "\
4262 "{e.jse_page_table_pages: >10d}"
4264 snapshot_list
= kern
.globals.memorystatus_jetsam_snapshot
.entries
4267 current_entry
= dereference(Cast(addressof(snapshot_list
[idx
]), 'jetsam_snapshot_entry *'))
4268 print entry_format
.format(index
=idx
, e
=current_entry
)
4272 # EndMacro: showjetsamsnapshot
4274 # Macro: showvnodecleanblk/showvnodedirtyblk
4276 def _GetBufSummary(buf
):
4277 """ Get a summary of important information out of a buf_t.
4279 initial
= "(struct buf) {0: <#0x} ="
4281 # List all of the fields in this buf summary.
4282 entries
= [buf
.b_hash
, buf
.b_vnbufs
, buf
.b_freelist
, buf
.b_timestamp
, buf
.b_whichq
,
4283 buf
.b_flags
, buf
.b_lflags
, buf
.b_error
, buf
.b_bufsize
, buf
.b_bcount
, buf
.b_resid
,
4284 buf
.b_dev
, buf
.b_datap
, buf
.b_lblkno
, buf
.b_blkno
, buf
.b_iodone
, buf
.b_vp
,
4285 buf
.b_rcred
, buf
.b_wcred
, buf
.b_upl
, buf
.b_real_bp
, buf
.b_act
, buf
.b_drvdata
,
4286 buf
.b_fsprivate
, buf
.b_transaction
, buf
.b_dirtyoff
, buf
.b_dirtyend
, buf
.b_validoff
,
4287 buf
.b_validend
, buf
.b_redundancy_flags
, buf
.b_proc
, buf
.b_attr
]
4289 # Join an (already decent) string representation of each field
4290 # with newlines and indent the region.
4291 joined_strs
= "\n".join([str(i
).rstrip() for i
in entries
]).replace('\n', "\n ")
4293 # Add the total string representation to our title and return it.
4294 out_str
= initial
.format(int(buf
)) + " {\n " + joined_strs + "\n}\n\n"
4297 def _ShowVnodeBlocks(dirty
=True, cmd_args
=None):
4298 """ Display info about all [dirty|clean] blocks in a vnode.
4300 if cmd_args
== None or len(cmd_args
) < 1:
4301 print "Please provide a valid vnode argument."
4304 vnodeval
= kern
.GetValueFromAddress(cmd_args
[0], 'vnode *')
4305 list_head
= vnodeval
.v_cleanblkhd
;
4307 list_head
= vnodeval
.v_dirtyblkhd
4309 print "Blocklist for vnode {}:".format(cmd_args
[0])
4312 for buf
in IterateListEntry(list_head
, 'struct buf *', 'b_hash'):
4313 # For each block (buf_t) in the appropriate list,
4314 # ask for a summary and print it.
4315 print "---->\nblock {}: ".format(i
) + _GetBufSummary(buf
)
4319 @lldb_command('showvnodecleanblk')
4320 def ShowVnodeCleanBlocks(cmd_args
=None):
4321 """ Display info about all clean blocks in a vnode.
4322 usage: showvnodecleanblk <address of vnode>
4324 _ShowVnodeBlocks(False, cmd_args
)
4326 @lldb_command('showvnodedirtyblk')
4327 def ShowVnodeDirtyBlocks(cmd_args
=None):
4328 """ Display info about all dirty blocks in a vnode.
4329 usage: showvnodedirtyblk <address of vnode>
4331 _ShowVnodeBlocks(True, cmd_args
)
4333 # EndMacro: showvnodecleanblk/showvnodedirtyblk
4336 @lldb_command("vm_page_lookup_in_map")
4337 def VmPageLookupInMap(cmd_args
=None):
4338 """Lookup up a page at a virtual address in a VM map
4339 usage: vm_page_lookup_in_map <map> <vaddr>
4341 if cmd_args
== None or len(cmd_args
) < 2:
4342 print "Invalid argument.", VmPageLookupInMap
.__doc
__
4344 map = kern
.GetValueFromAddress(cmd_args
[0], 'vm_map_t')
4345 vaddr
= kern
.GetValueFromAddress(cmd_args
[1], 'vm_map_offset_t')
4346 print "vaddr {:#018x} in map {: <#018x}".format(vaddr
, map)
4347 vm_page_lookup_in_map(map, vaddr
)
4349 def vm_page_lookup_in_map(map, vaddr
):
4350 vaddr
= unsigned(vaddr
)
4351 vme_list_head
= map.hdr
.links
4352 vme_ptr_type
= GetType('vm_map_entry *')
4353 for vme
in IterateQueue(vme_list_head
, vme_ptr_type
, "links"):
4354 if unsigned(vme
.links
.start
) > vaddr
:
4356 if unsigned(vme
.links
.end
) <= vaddr
:
4358 offset_in_vme
= vaddr
- unsigned(vme
.links
.start
)
4359 print " offset {:#018x} in map entry {: <#018x} [{:#018x}:{:#018x}] object {: <#018x} offset {:#018x}".format(offset_in_vme
, vme
, unsigned(vme
.links
.start
), unsigned(vme
.links
.end
), vme
.vme_object
.vmo_object
, unsigned(vme
.vme_offset
) & ~
0xFFF)
4360 offset_in_object
= offset_in_vme
+ (unsigned(vme
.vme_offset
) & ~
0xFFF)
4362 print "vaddr {:#018x} in map {: <#018x}".format(offset_in_object
, vme
.vme_object
.vmo_submap
)
4363 vm_page_lookup_in_map(vme
.vme_object
.vmo_submap
, offset_in_object
)
4365 vm_page_lookup_in_object(vme
.vme_object
.vmo_object
, offset_in_object
)
4367 @lldb_command("vm_page_lookup_in_object")
4368 def VmPageLookupInObject(cmd_args
=None):
4369 """Lookup up a page at a given offset in a VM object
4370 usage: vm_page_lookup_in_object <object> <offset>
4372 if cmd_args
== None or len(cmd_args
) < 2:
4373 print "Invalid argument.", VmPageLookupInObject
.__doc
__
4375 object = kern
.GetValueFromAddress(cmd_args
[0], 'vm_object_t')
4376 offset
= kern
.GetValueFromAddress(cmd_args
[1], 'vm_object_offset_t')
4377 print "offset {:#018x} in object {: <#018x}".format(offset
, object)
4378 vm_page_lookup_in_object(object, offset
)
4380 def vm_page_lookup_in_object(object, offset
):
4381 offset
= unsigned(offset
)
4382 page_size
= kern
.globals.page_size
4383 trunc_offset
= offset
& ~
(page_size
- 1)
4384 print " offset {:#018x} in VM object {: <#018x}".format(offset
, object)
4385 hash_id
= _calc_vm_page_hash(object, trunc_offset
)
4386 page_list
= kern
.globals.vm_page_buckets
[hash_id
].page_list
4387 page
= _vm_page_unpack_ptr(page_list
)
4389 m
= kern
.GetValueFromAddress(page
, 'vm_page_t')
4390 m_object_val
= _vm_page_unpack_ptr(m
.vmp_object
)
4391 m_object
= kern
.GetValueFromAddress(m_object_val
, 'vm_object_t')
4392 if unsigned(m_object
) != unsigned(object) or unsigned(m
.vmp_offset
) != unsigned(trunc_offset
):
4393 page
= _vm_page_unpack_ptr(m
.vmp_next_m
)
4395 print " resident page {: <#018x} phys {:#010x}".format(m
, _vm_page_get_phys_page(m
))
4397 if object.pager
and object.pager_ready
:
4398 offset_in_pager
= trunc_offset
+ unsigned(object.paging_offset
)
4399 if not object.internal
:
4400 print " offset {:#018x} in external '{:s}' {: <#018x}".format(offset_in_pager
, object.pager
.mo_pager_ops
.memory_object_pager_name
, object.pager
)
4402 pager
= Cast(object.pager
, 'compressor_pager *')
4403 ret
= vm_page_lookup_in_compressor_pager(pager
, offset_in_pager
)
4406 if object.shadow
and not object.phys_contiguous
:
4407 offset_in_shadow
= offset
+ unsigned(object.vo_un2
.vou_shadow_offset
)
4408 vm_page_lookup_in_object(object.shadow
, offset_in_shadow
)
4410 print " page is absent and will be zero-filled on demand"
4413 @lldb_command("vm_page_lookup_in_compressor_pager")
4414 def VmPageLookupInCompressorPager(cmd_args
=None):
4415 """Lookup up a page at a given offset in a compressor pager
4416 usage: vm_page_lookup_in_compressor_pager <pager> <offset>
4418 if cmd_args
== None or len(cmd_args
) < 2:
4419 print "Invalid argument.", VmPageLookupInCompressorPager
.__doc
__
4421 pager
= kern
.GetValueFromAddress(cmd_args
[0], 'compressor_pager_t')
4422 offset
= kern
.GetValueFromAddress(cmd_args
[1], 'memory_object_offset_t')
4423 print "offset {:#018x} in compressor pager {: <#018x}".format(offset
, pager
)
4424 vm_page_lookup_in_compressor_pager(pager
, offset
)
4426 def vm_page_lookup_in_compressor_pager(pager
, offset
):
4427 offset
= unsigned(offset
)
4428 page_size
= unsigned(kern
.globals.page_size
)
4429 page_num
= unsigned(offset
/ page_size
)
4430 if page_num
> pager
.cpgr_num_slots
:
4431 print " *** ERROR: vm_page_lookup_in_compressor_pager({: <#018x},{:#018x}): page_num {:#x} > num_slots {:#x}".format(pager
, offset
, page_num
, pager
.cpgr_num_slots
)
4433 slots_per_chunk
= 512 / sizeof ('compressor_slot_t')
4434 num_chunks
= unsigned((pager
.cpgr_num_slots
+slots_per_chunk
-1) / slots_per_chunk
)
4436 chunk_idx
= unsigned(page_num
/ slots_per_chunk
)
4437 chunk
= pager
.cpgr_slots
.cpgr_islots
[chunk_idx
]
4438 slot_idx
= unsigned(page_num
% slots_per_chunk
)
4439 slot
= GetObjectAtIndexFromArray(chunk
, slot_idx
)
4440 slot_str
= "islots[{:d}][{:d}]".format(chunk_idx
, slot_idx
)
4441 elif pager
.cpgr_num_slots
> 2:
4443 slot
= GetObjectAtIndexFromArray(pager
.cpgr_slots
.cpgr_dslots
, slot_idx
)
4444 slot_str
= "dslots[{:d}]".format(slot_idx
)
4447 slot
= GetObjectAtIndexFromArray(pager
.cpgr_slots
.cpgr_eslots
, slot_idx
)
4448 slot_str
= "eslots[{:d}]".format(slot_idx
)
4449 print " offset {:#018x} in compressor pager {: <#018x} {:s} slot {: <#018x}".format(offset
, pager
, slot_str
, slot
)
4452 slot_value
= dereference(slot
)
4453 print " value {:#010x}".format(slot_value
)
4454 vm_page_lookup_in_compressor(Cast(slot
, 'c_slot_mapping_t'))
4457 @lldb_command("vm_page_lookup_in_compressor")
4458 def VmPageLookupInCompressor(cmd_args
=None):
4459 """Lookup up a page in a given compressor slot
4460 usage: vm_page_lookup_in_compressor <slot>
4462 if cmd_args
== None or len(cmd_args
) < 1:
4463 print "Invalid argument.", VmPageLookupInCompressor
.__doc
__
4465 slot
= kern
.GetValueFromAddress(cmd_args
[0], 'compressor_slot_t *')
4466 print "compressor slot {: <#018x}".format(slot
)
4467 vm_page_lookup_in_compressor(slot
)
4469 C_SV_CSEG_ID
= ((1 << 22) - 1)
4471 def vm_page_lookup_in_compressor(slot_ptr
):
4472 slot_ptr
= Cast(slot_ptr
, 'compressor_slot_t *')
4473 slot_value
= dereference(slot_ptr
)
4474 slot
= Cast(slot_value
, 'c_slot_mapping')
4476 print "compressor slot {: <#018x} -> {:#010x} cseg {:d} cindx {:d}".format(unsigned(slot_ptr
), unsigned(slot_value
), slot
.s_cseg
, slot
.s_cindx
)
4479 if slot
.s_cseg
== C_SV_CSEG_ID
:
4480 sv
= kern
.globals.c_segment_sv_hash_table
4481 print "single value[{:#d}]: ref {:d} value {:#010x}".format(slot
.s_cindx
, sv
[slot
.s_cindx
].c_sv_he_un
.c_sv_he
.c_sv_he_ref
, sv
[slot
.s_cindx
].c_sv_he_un
.c_sv_he
.c_sv_he_data
)
4483 if slot
.s_cseg
== 0 or unsigned(slot
.s_cseg
) > unsigned(kern
.globals.c_segments_available
):
4484 print "*** ERROR: s_cseg {:d} is out of bounds (1 - {:d})".format(slot
.s_cseg
, unsigned(kern
.globals.c_segments_available
))
4486 c_segments
= kern
.globals.c_segments
4487 c_segments_elt
= GetObjectAtIndexFromArray(c_segments
, slot
.s_cseg
-1)
4488 c_seg
= c_segments_elt
.c_seg
4490 if hasattr(c_seg
, 'c_state'):
4491 c_state
= c_seg
.c_state
4493 c_state_str
= "C_IS_EMPTY"
4496 c_state_str
= "C_IS_FREE"
4499 c_state_str
= "C_IS_FILLING"
4501 c_state_str
= "C_ON_AGE_Q"
4503 c_state_str
= "C_ON_SWAPOUT_Q"
4505 c_state_str
= "C_ON_SWAPPEDOUT_Q"
4508 c_state_str
= "C_ON_SWAPPEDOUTSPARSE_Q"
4511 c_state_str
= "C_ON_SWAPPEDIN_Q"
4513 c_state_str
= "C_ON_MAJORCOMPACT_Q"
4515 c_state_str
= "C_ON_BAD_Q"
4518 c_state_str
= "<unknown>"
4521 c_state_str
= "<no c_state field>"
4522 print "c_segments[{:d}] {: <#018x} c_seg {: <#018x} c_state {:#x}={:s}".format(slot
.s_cseg
-1, c_segments_elt
, c_seg
, c_state
, c_state_str
)
4523 c_indx
= unsigned(slot
.s_cindx
)
4524 if hasattr(c_seg
, 'c_slot_var_array'):
4525 c_seg_fixed_array_len
= kern
.globals.c_seg_fixed_array_len
4526 if c_indx
< c_seg_fixed_array_len
:
4527 cs
= c_seg
.c_slot_fixed_array
[c_indx
]
4529 cs
= GetObjectAtIndexFromArray(c_seg
.c_slot_var_array
, c_indx
- c_seg_fixed_array_len
)
4531 C_SEG_SLOT_ARRAY_SIZE
= 64
4532 C_SEG_SLOT_ARRAY_MASK
= C_SEG_SLOT_ARRAY_SIZE
- 1
4533 cs
= GetObjectAtIndexFromArray(c_seg
.c_slots
[c_indx
/ C_SEG_SLOT_ARRAY_SIZE
], c_indx
& C_SEG_SLOT_ARRAY_MASK
)
4535 c_slot_unpacked_ptr
= vm_unpack_ptr(cs
.c_packed_ptr
, kern
.globals.c_slot_packing_params
)
4536 print "c_slot {: <#018x} c_offset {:#x} c_size {:#x} c_packed_ptr {:#x} (unpacked: {: <#018x})".format(cs
, cs
.c_offset
, cs
.c_size
, cs
.c_packed_ptr
, unsigned(c_slot_unpacked_ptr
))
4537 if unsigned(slot_ptr
) != unsigned(c_slot_unpacked_ptr
):
4538 print "*** ERROR: compressor slot {: <#018x} points back to {: <#018x} instead of itself".format(slot_ptr
, c_slot_unpacked_ptr
)
4540 c_data
= c_seg
.c_store
.c_buffer
+ (4 * cs
.c_offset
)
4542 cmd
= "memory read {: <#018x} {: <#018x} --force".format(c_data
, c_data
+ c_size
)
4544 print lldb_run_command(cmd
)
4546 print "<no compressed data>"
4548 def print_hex_data(data
, begin_offset
=0, desc
=""):
4549 """ print on stdout "hexdump -C < data" like output
4551 data - bytearray or array of int where each int < 255
4552 begin_offset - int offset that should be printed in left column
4553 desc - str optional description to print on the first line to describe data
4556 print "{}:".format(desc
)
4558 total_len
= len(data
)
4561 while index
< total_len
:
4562 hex_buf
+= " {:02x}".format(data
[index
])
4563 if data
[index
] < 0x20 or data
[index
] > 0x7e:
4566 char_buf
+= "{:c}".format(data
[index
])
4568 if index
and index
% 8 == 0:
4570 if index
> 1 and (index
% 16) == 0:
4571 print "{:08x} {: <50s} |{: <16s}|".format(begin_offset
+ index
- 16, hex_buf
, char_buf
)
4575 print "{:08x} {: <50s} |{: <16s}|".format(begin_offset
+ index
- 16, hex_buf
, char_buf
)
4578 @lldb_command('vm_scan_all_pages')
4579 def VMScanAllPages(cmd_args
=None):
4580 """Scans the vm_pages[] array
4582 vm_pages_count
= kern
.globals.vm_pages_count
4583 vm_pages
= kern
.globals.vm_pages
4586 local_free_count
= 0
4588 local_active_count
= 0
4590 speculative_count
= 0
4593 compressor_count
= 0
4594 pageable_internal_count
= 0
4595 pageable_external_count
= 0
4597 secluded_free_count
= 0
4598 secluded_inuse_count
= 0
4601 while i
< vm_pages_count
:
4604 print "{:d}/{:d}...\n".format(i
,vm_pages_count
)
4610 m_object_val
= _vm_page_unpack_ptr(m
.vmp_object
)
4613 if m_object
.internal
:
4618 if m
.vmp_wire_count
!= 0 and m
.vmp_local
== 0:
4619 wired_count
= wired_count
+ 1
4621 elif m
.vmp_throttled
:
4622 throttled_count
= throttled_count
+ 1
4625 active_count
= active_count
+ 1
4628 local_active_count
= local_active_count
+ 1
4630 elif m
.vmp_inactive
:
4631 inactive_count
= inactive_count
+ 1
4633 elif m
.vmp_speculative
:
4634 speculative_count
= speculative_count
+ 1
4637 free_count
= free_count
+ 1
4639 elif m
.vmp_secluded
:
4640 secluded_count
= secluded_count
+ 1
4642 secluded_free_count
= secluded_free_count
+ 1
4644 secluded_inuse_count
= secluded_inuse_count
+ 1
4646 elif m_object
== 0 and m
.vmp_busy
:
4647 local_free_count
= local_free_count
+ 1
4649 elif m
.vmp_compressor
:
4650 compressor_count
= compressor_count
+ 1
4653 print "weird page vm_pages[{:d}]?\n".format(i
)
4658 pageable_internal_count
= pageable_internal_count
+ 1
4660 pageable_external_count
= pageable_external_count
+ 1
4663 print "vm_pages_count = {:d}\n".format(vm_pages_count
)
4665 print "wired_count = {:d}\n".format(wired_count
)
4666 print "throttled_count = {:d}\n".format(throttled_count
)
4667 print "active_count = {:d}\n".format(active_count
)
4668 print "local_active_count = {:d}\n".format(local_active_count
)
4669 print "inactive_count = {:d}\n".format(inactive_count
)
4670 print "speculative_count = {:d}\n".format(speculative_count
)
4671 print "free_count = {:d}\n".format(free_count
)
4672 print "local_free_count = {:d}\n".format(local_free_count
)
4673 print "compressor_count = {:d}\n".format(compressor_count
)
4675 print "pageable_internal_count = {:d}\n".format(pageable_internal_count
)
4676 print "pageable_external_count = {:d}\n".format(pageable_external_count
)
4677 print "secluded_count = {:d}\n".format(secluded_count
)
4678 print "secluded_free_count = {:d}\n".format(secluded_free_count
)
4679 print "secluded_inuse_count = {:d}\n".format(secluded_inuse_count
)
4682 @lldb_command('show_all_vm_named_entries')
4683 def ShowAllVMNamedEntries(cmd_args
=None):
4684 """ Routine to print a summary listing of all the VM named entries
4686 queue_len
= kern
.globals.vm_named_entry_count
4687 queue_head
= kern
.globals.vm_named_entry_list
4689 print 'vm_named_entry_list:{: <#018x} vm_named_entry_count:{:d}\n'.format(kern
.GetLoadAddressForSymbol('vm_named_entry_list'),queue_len
)
4691 # print '{:>6s} {:<6s} {:18s} {:1s} {:>6s} {:>16s} {:>10s} {:>10s} {:>10s} {:>3s} {:18s} {:>6s} {:<20s}\n'.format("#","#","object","P","refcnt","size (pages)","resid","wired","compressed","tag","owner","pid","process")
4693 for entry
in IterateQueue(queue_head
, 'struct vm_named_entry *', 'named_entry_list'):
4695 showmemoryentry(entry
, idx
, queue_len
)
4697 @lldb_command('show_vm_named_entry')
4698 def ShowVMNamedEntry(cmd_args
=None):
4699 """ Routine to print a VM named entry
4701 if cmd_args
== None or len(cmd_args
) < 1:
4702 print "Invalid argument.", ShowMapVMNamedEntry
.__doc
__
4704 named_entry
= kern
.GetValueFromAddress(cmd_args
[0], 'vm_named_entry_t')
4705 showmemoryentry(named_entry
, 0, 0)
4707 def showmemoryentry(entry
, idx
=0, queue_len
=0):
4708 """ Routine to print out a summary a VM memory entry
4710 entry - core.value : a object of type 'struct vm_named_entry *'
4714 show_pager_info
= True
4715 show_all_shadows
= True
4718 if entry
.is_sub_map
== 1:
4720 if entry
.is_copy
== 1:
4722 if entry
.is_object
== 1:
4724 if entry
.is_sub_map
== 0 and entry
.is_copy
== 0 and entry
.is_object
== 0:
4725 backing
+= "***?***"
4727 if entry
.protection
& 0x1:
4731 if entry
.protection
& 0x2:
4735 if entry
.protection
& 0x4:
4740 if hasattr(entry
, 'named_entry_alias'):
4741 extra_str
+= " alias={:d}".format(entry
.named_entry_alias
)
4742 if hasattr(entry
, 'named_entry_port'):
4743 extra_str
+= " port={:#016x}".format(entry
.named_entry_port
)
4744 print "{:d}/{:d} {: <#018x} ref={:d} prot={:d}/{:s} type={:s} backing={: <#018x} offset={:#016x} dataoffset={:#016x} size={:#016x}{:s}\n".format(idx
,queue_len
,entry
,entry
.ref_count
,entry
.protection
,prot
,backing
,entry
.backing
.copy
,entry
.offset
,entry
.data_offset
,entry
.size
,extra_str
)
4745 if entry
.is_sub_map
== 1:
4746 showmapvme(entry
.backing
.map, 0, 0, show_pager_info
, show_all_shadows
)
4747 elif entry
.is_copy
== 1:
4748 showmapcopyvme(entry
.backing
.copy
, 0, 0, show_pager_info
, show_all_shadows
, 0)
4749 elif entry
.is_object
== 1:
4750 showmapcopyvme(entry
.backing
.copy
, 0, 0, show_pager_info
, show_all_shadows
, 0)
4752 print "***** UNKNOWN TYPE *****"
4756 def IterateRBTreeEntry2(element
, element_type
, field_name1
, field_name2
):
4757 """ iterate over a rbtree as defined with RB_HEAD in libkern/tree.h
4758 element - value : Value object for rbh_root
4759 element_type - str : Type of the link element
4760 field_name - str : Name of the field in link element's structure
4762 A generator does not return. It is used for iterating
4763 value : an object thats of type (element_type) head->sle_next. Always a pointer object
4765 elt
= element
.__getattr
__('rbh_root')
4766 if type(element_type
) == str:
4767 element_type
= gettype(element_type
)
4768 charp_type
= gettype('char *');
4772 while unsigned(elt
) != 0:
4774 elt
= cast(elt
.__getattr
__(field_name1
).__getattr
__(field_name2
).__getattr
__('rbe_left'), element_type
)
4778 while unsigned(elt
) != 0:
4780 # implementation cribbed from RB_NEXT in libkern/tree.h
4781 right
= cast(elt
.__getattr
__(field_name1
).__getattr
__(fieldname2
).__getattr
__('rbe_right'), element_type
)
4782 if unsigned(right
) != 0:
4784 left
= cast(elt
.__getattr
__(field_name1
).__getattr
__(field_name2
).__getattr
__('rbe_left'), element_type
)
4785 while unsigned(left
) != 0:
4787 left
= cast(elt
.__getattr
__(field_name1
).__getattr
(__field_name2
).__getattr
__('rbe_left'), element_type
)
4790 # avoid using GetValueFromAddress
4791 addr
= elt
.__getattr
__(field_name1
).__getattr
__(field_name2
).__getattr
__('rbe_parent')&~
1
4792 parent
= value(elt
.GetSBValue().CreateValueFromExpression(None,'(void *)'+str(addr
)))
4793 parent
= cast(parent
, element_type
)
4795 if unsigned(parent
) != 0:
4796 left
= cast(parent
.__getattr
__(field_name1
).__getattr
__(field_name2
).__getattr
__('rbe_left'), element_type
)
4797 if (unsigned(parent
) != 0) and (unsigned(elt
) == unsigned(left
)):
4800 if unsigned(parent
) != 0:
4801 right
= cast(parent
.__getattr
__(field_name1
).__getattr
__(field_name2
).__getattr
__('rbe_right'), element_type
)
4802 while unsigned(parent
) != 0 and (unsigned(elt
) == unsigned(right
)):
4805 # avoid using GetValueFromAddress
4806 addr
= elt
.__getattr
__(field_name1
).__getattr
__(field_name2
).__getattr
__('rbe_parent')&~
1
4807 parent
= value(elt
.GetSBValue().CreateValueFromExpression(None,'(void *)'+str(addr
)))
4808 parent
= cast(parent
, element_type
)
4810 right
= cast(parent
.__getattr
__(field_name1
).__getattr
__(field_name2
).__getattr
__('rbe_right'), element_type
)
4812 # avoid using GetValueFromAddress
4813 addr
= elt
.__getattr
__(field_name1
).__getattr
__(field_name2
).__getattr
__('rbe_parent')&~
1
4814 elt
= value(elt
.GetSBValue().CreateValueFromExpression(None,'(void *)'+str(addr
)))
4815 elt
= cast(elt
, element_type
)
4818 @lldb_command("showmaprb")
4819 def ShowMapRB(cmd_args
=None):
4820 """Routine to print out a VM map's RB tree
4821 usage: showmaprb <vm_map>
4823 if cmd_args
== None or len(cmd_args
) < 1:
4824 print "Invalid argument.", ShowMapRB
.__doc
__
4826 map_val
= kern
.GetValueFromAddress(cmd_args
[0], 'vm_map_t')
4827 print GetVMMapSummary
.header
4828 print GetVMMapSummary(map_val
)
4829 vme_rb_root
= map_val
.hdr
.rb_head_store
4830 vme_ptr_type
= GetType('struct vm_map_entry *')
4831 print GetVMEntrySummary
.header
4832 for vme
in IterateRBTreeEntry2(vme_rb_root
, 'struct vm_map_entry *', 'store', 'entry'):
4833 print GetVMEntrySummary(vme
)
4836 @lldb_command('show_all_owned_objects', 'T')
4837 def ShowAllOwnedObjects(cmd_args
=None, cmd_options
={}):
4838 """ Routine to print the list of VM objects owned by each task
4839 -T: show only ledger-tagged objects
4841 showonlytagged
= False
4842 if "-T" in cmd_options
:
4843 showonlytagged
= True
4844 for task
in kern
.tasks
:
4845 ShowTaskOwnedVmObjects(task
, showonlytagged
)
4847 @lldb_command('show_task_owned_objects', 'T')
4848 def ShowTaskOwnedObjects(cmd_args
=None, cmd_options
={}):
4849 """ Routine to print the list of VM objects owned by the specified task
4850 -T: show only ledger-tagged objects
4852 showonlytagged
= False
4853 if "-T" in cmd_options
:
4854 showonlytagged
= True
4855 task
= kern
.GetValueFromAddress(cmd_args
[0], 'task *')
4856 ShowTaskOwnedVmObjects(task
, showonlytagged
)
4858 @lldb_command('showdeviceinfo', 'J')
4859 def ShowDeviceInfo(cmd_args
=None, cmd_options
={}):
4860 """ Routine to show basic device information (model, build, ncpus, etc...)
4861 Usage: memstats [-J]
4865 if "-J" in cmd_options
:
4868 device_info
["build"] = str(kern
.globals.osversion
)
4869 device_info
["memoryConfig"] = int(kern
.globals.max_mem_actual
)
4870 device_info
["ncpu"] = int(kern
.globals.ncpu
)
4871 device_info
["pagesize"] = int(kern
.globals.page_size
)
4872 device_info
["mlockLimit"] = long(kern
.globals.vm_global_user_wire_limit
)
4876 print json
.dumps(device_info
)
4878 PrettyPrintDictionary(device_info
)
4880 def ShowTaskOwnedVmObjects(task
, showonlytagged
=False):
4881 """ Routine to print out a summary listing of all the entries in a vm_map
4883 task - core.value : a object of type 'task *'
4887 taskobjq_total
= lambda:None
4888 taskobjq_total
.objects
= 0
4889 taskobjq_total
.vsize
= 0
4890 taskobjq_total
.rsize
= 0
4891 taskobjq_total
.wsize
= 0
4892 taskobjq_total
.csize
= 0
4893 vmo_list_head
= task
.task_objq
4894 vmo_ptr_type
= GetType('vm_object *')
4896 for vmo
in IterateQueue(vmo_list_head
, vmo_ptr_type
, "task_objq"):
4898 if not showonlytagged
or vmo
.vo_ledger_tag
!= 0:
4899 if taskobjq_total
.objects
== 0:
4901 print GetTaskSummary
.header
+ ' ' + GetProcSummary
.header
4902 print GetTaskSummary(task
) + ' ' + GetProcSummary(Cast(task
.bsd_info
, 'proc *'))
4903 print '{:>6s} {:<6s} {:18s} {:1s} {:>6s} {:>16s} {:>10s} {:>10s} {:>10s} {:>2s} {:18s} {:>6s} {:<20s}\n'.format("#","#","object","P","refcnt","size (pages)","resid","wired","compressed","tg","owner","pid","process")
4904 ShowOwnedVmObject(vmo
, idx
, 0, taskobjq_total
)
4905 if taskobjq_total
.objects
!= 0:
4906 print " total:{:<10d} [ virtual:{:<10d} resident:{:<10d} wired:{:<10d} compressed:{:<10d} ]\n".format(taskobjq_total
.objects
, taskobjq_total
.vsize
, taskobjq_total
.rsize
, taskobjq_total
.wsize
, taskobjq_total
.csize
)
4909 def ShowOwnedVmObject(object, idx
, queue_len
, taskobjq_total
):
4910 """ Routine to print out a VM object owned by a task
4912 object - core.value : a object of type 'struct vm_object *'
4916 page_size
= kern
.globals.page_size
4917 if object.purgable
== 0:
4919 elif object.purgable
== 1:
4921 elif object.purgable
== 2:
4923 elif object.purgable
== 3:
4927 if object.pager
== 0:
4928 compressed_count
= 0
4930 compressor_pager
= Cast(object.pager
, 'compressor_pager *')
4931 compressed_count
= compressor_pager
.cpgr_num_slots_occupied
4933 print "{:>6d}/{:<6d} {: <#018x} {:1s} {:>6d} {:>16d} {:>10d} {:>10d} {:>10d} {:>2d} {: <#018x} {:>6d} {:<20s}\n".format(idx
,queue_len
,object,purgable
,object.ref_count
,object.vo_un1
.vou_size
/page_size
,object.resident_page_count
,object.wired_page_count
,compressed_count
, object.vo_ledger_tag
, object.vo_un2
.vou_owner
,GetProcPIDForObjectOwner(object.vo_un2
.vou_owner
),GetProcNameForObjectOwner(object.vo_un2
.vou_owner
))
4935 taskobjq_total
.objects
+= 1
4936 taskobjq_total
.vsize
+= object.vo_un1
.vou_size
/page_size
4937 taskobjq_total
.rsize
+= object.resident_page_count
4938 taskobjq_total
.wsize
+= object.wired_page_count
4939 taskobjq_total
.csize
+= compressed_count
4941 def GetProcPIDForObjectOwner(owner
):
4942 """ same as GetProcPIDForTask() but deals with -1 for a disowned object
4944 if unsigned(Cast(owner
, 'int')) == unsigned(int(0xffffffff)):
4946 return GetProcPIDForTask(owner
)
4948 def GetProcNameForObjectOwner(owner
):
4949 """ same as GetProcNameForTask() but deals with -1 for a disowned object
4951 if unsigned(Cast(owner
, 'int')) == unsigned(int(0xffffffff)):
4953 return GetProcNameForTask(owner
)
4955 def GetDescForNamedEntry(mem_entry
):
4957 out_str
+= "\t\tmem_entry {:#08x} ref:{:d} offset:{:#08x} size:{:#08x} prot{:d} backing {:#08x}".format(mem_entry
, mem_entry
.ref_count
, mem_entry
.offset
, mem_entry
.size
, mem_entry
.protection
, mem_entry
.backing
.copy
)
4958 if mem_entry
.is_sub_map
:
4959 out_str
+= " is_sub_map"
4960 elif mem_entry
.is_copy
:
4961 out_str
+= " is_copy"
4962 elif mem_entry
.is_object
:
4963 out_str
+= " is_object"