]> git.saurik.com Git - apple/xnu.git/blame - tools/lldbmacros/memory.py
xnu-2422.1.72.tar.gz
[apple/xnu.git] / tools / lldbmacros / memory.py
CommitLineData
39236c6e
A
1
2""" Please make sure you read the README file COMPLETELY BEFORE reading anything below.
3 It is very critical that you read coding guidelines in Section E in README file.
4"""
5from xnu import *
6import sys, shlex
7from utils import *
8import xnudefines
9from process import *
10
11# Macro: memstats
12@lldb_command('memstats')
13def Memstats(cmd_args=None):
14 """ Prints out a summary of various memory statistics. In particular vm_page_wire_count should be greater than 2K or you are under memory pressure.
15 """
16 try:
17 print "memorystatus_level: {: >10d}".format(kern.globals.memorystatus_level)
18 except ValueError:
19 pass
20 try:
21 print "memorystatus_available_pages: {: >10d}".format(kern.globals.memorystatus_available_pages)
22 except ValueError:
23 pass
24 print "vm_page_throttled_count: {: >10d}".format(kern.globals.vm_page_throttled_count)
25 print "vm_page_active_count: {: >10d}".format(kern.globals.vm_page_active_count)
26 print "vm_page_inactive_count: {: >10d}".format(kern.globals.vm_page_inactive_count)
27 print "vm_page_wire_count: {: >10d}".format(kern.globals.vm_page_wire_count)
28 print "vm_page_free_count: {: >10d}".format(kern.globals.vm_page_free_count)
29 print "vm_page_purgeable_count: {: >10d}".format(kern.globals.vm_page_purgeable_count)
30 print "vm_page_inactive_target: {: >10d}".format(kern.globals.vm_page_inactive_target)
31 print "vm_page_free_target: {: >10d}".format(kern.globals.vm_page_free_target)
32 print "inuse_ptepages_count: {: >10d}".format(kern.globals.inuse_ptepages_count)
33 print "vm_page_free_reserved: {: >10d}".format(kern.globals.vm_page_free_reserved)
34
35@xnudebug_test('test_memstats')
36def TestMemstats(kernel_target, config, lldb_obj, isConnected ):
37 """ Test the functionality of memstats command
38 returns
39 - False on failure
40 - True on success
41 """
42 if not isConnected:
43 print "Target is not connected. Cannot test memstats"
44 return False
45 res = lldb.SBCommandReturnObject()
46 lldb_obj.debugger.GetCommandInterpreter().HandleCommand("memstats", res)
47 result = res.GetOutput()
48 if result.split(":")[1].strip().find('None') == -1 :
49 return True
50 else:
51 return False
52
53# EndMacro: memstats
54
55# Macro: showmemorystatus
56def CalculateLedgerPeak(phys_footprint_entry):
57 """ Internal function to calculate ledger peak value for the given phys footprint entry
58 params: phys_footprint_entry - value representing struct ledger_entry *
59 return: value - representing the ledger peak for the given phys footprint entry
60 """
61 now = kern.globals.sched_tick / 20
62 ledger_peak = phys_footprint_entry.le_credit - phys_footprint_entry.le_debit
63 if (now - phys_footprint_entry._le.le_peaks[0].le_time <= 1) and (phys_footprint_entry._le.le_peaks[0].le_max > ledger_peak):
64 ledger_peak = phys_footprint_entry._le.le_peaks[0].le_max
65 if (now - phys_footprint_entry._le.le_peaks[1].le_time <= 1) and (phys_footprint_entry._le.le_peaks[1].le_max > ledger_peak):
66 ledger_peak = phys_footprint_entry._le.le_peaks[1].le_max
67 return ledger_peak
68
69@header("{: >8s} {: >22s} {: >22s} {: >11s} {: >11s} {: >12s} {: >10s} {: >13s} {: ^10s} {: >8s} {: <20s}\n".format(
70'pid', 'effective priority', 'requested priority', 'state', 'user_data', 'physical', 'iokit', 'footprint',
71'spike', 'limit', 'command'))
72def GetMemoryStatusNode(proc_val):
73 """ Internal function to get memorystatus information from the given proc
74 params: proc - value representing struct proc *
75 return: str - formatted output information for proc object
76 """
77 out_str = ''
78 task_val = Cast(proc_val.task, 'task *')
79 task_ledgerp = task_val.ledger
80
81 task_physmem_footprint_ledger_entry = task_ledgerp.l_entries[kern.globals.task_ledgers.phys_mem]
82 task_iokit_footprint_ledger_entry = task_ledgerp.l_entries[kern.globals.task_ledgers.iokit_mem]
83 task_phys_footprint_ledger_entry = task_ledgerp.l_entries[kern.globals.task_ledgers.phys_footprint]
84 page_size = kern.globals.page_size
85
86 phys_mem_footprint = (task_physmem_footprint_ledger_entry.le_credit - task_physmem_footprint_ledger_entry.le_debit) / page_size
87 iokit_footprint = (task_iokit_footprint_ledger_entry.le_credit - task_iokit_footprint_ledger_entry.le_debit) / page_size
88 phys_footprint = (task_phys_footprint_ledger_entry.le_credit - task_phys_footprint_ledger_entry.le_debit) / page_size
89 phys_footprint_limit = task_phys_footprint_ledger_entry.le_limit / page_size
90 ledger_peak = CalculateLedgerPeak(task_phys_footprint_ledger_entry)
91 phys_footprint_spike = ledger_peak / page_size
92
93 format_string = '{0: >8d} {1: >22d} {2: >22d} {3: #011x} {4: #011x} {5: >12d} {6: >10d} {7: >13d}'
94 out_str += format_string.format(proc_val.p_pid, proc_val.p_memstat_effectivepriority,
95 proc_val.p_memstat_requestedpriority, proc_val.p_memstat_state, proc_val.p_memstat_userdata,
96 phys_mem_footprint, iokit_footprint, phys_footprint)
97 if phys_footprint != phys_footprint_spike:
98 out_str += "{: ^12d}".format(phys_footprint_spike)
99 else:
100 out_str += "{: ^12s}".format('-')
101 out_str += "{: 8d} {: <20s}\n".format(phys_footprint_limit, proc_val.p_comm)
102 return out_str
103
104@lldb_command('showmemorystatus')
105def ShowMemoryStatus(cmd_args=None):
106 """ Routine to display each entry in jetsam list with a summary of pressure statistics
107 Usage: showmemorystatus
108 """
109 bucket_index = 0
110 bucket_count = 20
111 print GetMemoryStatusNode.header
112 print "{: >91s} {: >10s} {: >13s} {: ^10s} {: >8s}\n".format("(pages)", "(pages)", "(pages)",
113 "(pages)", "(pages)")
114 while bucket_index < bucket_count:
115 current_bucket = kern.globals.memstat_bucket[bucket_index]
116 current_list = current_bucket.list
117 current_proc = Cast(current_list.tqh_first, 'proc *')
118 while unsigned(current_proc) != 0:
119 print GetMemoryStatusNode(current_proc)
120 current_proc = current_proc.p_memstat_list.tqe_next
121 bucket_index += 1
122 print "\n\n"
123 Memstats()
124
125# EndMacro: showmemorystatus
126
127# Macro: zprint
128
129@lldb_type_summary(['zone','zone_t'])
130@header("{:^18s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s}({:>6s} {:>6s} {:>6s}) {:^14s} {:<20s}".format(
131'ZONE', 'TOT_SZ', 'PAGE_COUNT', 'ALLOC_ELTS', 'FREE_ELTS', 'FREE_SZ', 'ELT_SZ', 'ALLOC', 'ELTS', 'PGS', 'SLK', 'FLAGS', 'NAME'))
132def GetZoneSummary(zone):
133 """ Summarize a zone with important information. See help zprint for description of each field
134 params:
135 zone: value - obj representing a zone in kernel
136 returns:
137 str - summary of the zone
138 """
139 out_string = ""
140 format_string = '{:#018x} {:10d} {:10d} {:10d} {:10d} {:10d} {:10d} {:10d} {:6d} {:6d} {:6d} {markings} {name:s} '
141 pagesize = 4096
142
143 free_elements = (zone.cur_size / zone.elem_size) - zone.count
144 free_size = free_elements * zone.elem_size
145
146 alloc_count = zone.alloc_size / zone.elem_size
147 alloc_pages = zone.alloc_size / pagesize
148 alloc_slack = zone.alloc_size % zone.elem_size
149 marks = [
150 ["collectable", "C"],
151 ["expandable", "X"],
152 ["noencrypt", "$"],
153 ["caller_acct", "@"],
154 ["exhaustible", "H"],
155 ["allows_foreign", "F"],
156 ["async_prio_refill", "R"],
157 ["no_callout", "O"],
158 ["zleak_on", "L"],
159 ["doing_alloc", "A"],
160 ["waiting", "W"],
161 ["doing_gc", "G"]
162 ]
163 if kern.arch == 'x86_64':
164 marks.append(["gzalloc_exempt", "M"])
165 marks.append(["alignment_required", "N"])
166
167 markings=""
168 for mark in marks:
169 if zone.__getattr__(mark[0]) :
170 markings+=mark[1]
171 else:
172 markings+=" "
173 out_string += format_string.format(zone, zone.cur_size, zone.page_count,
174 zone.count, free_elements, free_size,
175 zone.elem_size, zone.alloc_size, alloc_count,
176 alloc_pages, alloc_slack, name = zone.zone_name, markings=markings)
177
178 if zone.exhaustible :
179 out_string += "(max: {:d})".format(zone.max_size)
180
181 return out_string
182
183@lldb_command('zprint')
184def Zprint(cmd_args=None):
185 """ Routine to print a summary listing of all the kernel zones
186 All columns are printed in decimal
187 Legend:
188 C - collectable
189 X - expandable
190 $ - not encrypted during hibernation
191 @ - allocs and frees are accounted to caller process for KPRVT
192 H - exhaustible
193 F - allows foreign memory (memory not allocated from zone_map)
194 M - gzalloc will avoid monitoring this zone
195 R - will be refilled when below low water mark
196 O - does not allow refill callout to fill zone on noblock allocation
197 N - zone requires alignment (avoids padding this zone for debugging)
198 A - currently trying to allocate more backing memory from kernel_memory_allocate
199 W - another thread is waiting for more memory
200 L - zone is being monitored by zleaks
201 G - currently running GC
202 """
203 global kern
204 print GetZoneSummary.header
205 for zval in kern.zones:
206 print GetZoneSummary(zval)
207
208@xnudebug_test('test_zprint')
209def TestZprint(kernel_target, config, lldb_obj, isConnected ):
210 """ Test the functionality of zprint command
211 returns
212 - False on failure
213 - True on success
214 """
215 if not isConnected:
216 print "Target is not connected. Cannot test memstats"
217 return False
218 res = lldb.SBCommandReturnObject()
219 lldb_obj.debugger.GetCommandInterpreter().HandleCommand("zprint", res)
220 result = res.GetOutput()
221 if len(result.split("\n")) > 2:
222 return True
223 else:
224 return False
225
226
227# EndMacro: zprint
228
229# Macro: showzfreelist
230
231def ShowZfreeListHeader(zone):
232 """ Helper routine to print a header for zone freelist.
233 (Since the freelist does not have a custom type, this is not defined as a Type Summary).
234 params:
235 zone:zone_t - Zone object to print header info
236 returns:
237 None
238 """
239 out_str = ""
240 out_str += "{0: <9s} {1: <12s} {2: <18s} {3: <18s} {4: <6s}\n".format('ELEM_SIZE', 'COUNT', 'NCOOKIE', 'PCOOKIE', 'FACTOR')
241 out_str += "{0: <9d} {1: <12d} 0x{2:0>16x} 0x{3:0>16x} {4: <2d}/{5: <2d}\n\n".format(
242 zone.elem_size, zone.count, kern.globals.zp_nopoison_cookie, kern.globals.zp_poisoned_cookie, zone.zp_count, kern.globals.zp_factor)
243 out_str += "{0: <7s} {1: <18s} {2: <18s} {3: <18s} {4: <18s} {5: <18s} {6: <14s}\n".format(
244 'NUM', 'ELEM', 'NEXT', 'BACKUP', '^ NCOOKIE', '^ PCOOKIE', 'POISON (PREV)')
245 print out_str
246
247def ShowZfreeListChain(zone, zfirst, zlimit):
248 """ Helper routine to print a zone free list chain
249 params:
250 zone: zone_t - Zone object
251 zfirst: void * - A pointer to the first element of the free list chain
252 zlimit: int - Limit for the number of elements to be printed by showzfreelist
253 returns:
254 None
255 """
256 current = Cast(zfirst, 'void *')
257 while ShowZfreeList.elts_found < zlimit:
258 ShowZfreeList.elts_found += 1
259 znext = dereference(Cast(current, 'vm_offset_t *'))
260 backup_ptr = kern.GetValueFromAddress((unsigned(Cast(current, 'vm_offset_t')) + unsigned(zone.elem_size) - sizeof('vm_offset_t')), 'vm_offset_t *')
261 backup_val = dereference(backup_ptr)
262 n_unobfuscated = (unsigned(backup_val) ^ unsigned(kern.globals.zp_nopoison_cookie))
263 p_unobfuscated = (unsigned(backup_val) ^ unsigned(kern.globals.zp_poisoned_cookie))
264 poison_str = ''
265 if p_unobfuscated == unsigned(znext):
266 poison_str = "P ({0: <d})".format(ShowZfreeList.elts_found - ShowZfreeList.last_poisoned)
267 ShowZfreeList.last_poisoned = ShowZfreeList.elts_found
268 else:
269 if n_unobfuscated != unsigned(znext):
270 poison_str = "INVALID"
271 print "{0: <7d} 0x{1:0>16x} 0x{2:0>16x} 0x{3:0>16x} 0x{4:0>16x} 0x{5:0>16x} {6: <14s}\n".format(
272 ShowZfreeList.elts_found, unsigned(current), unsigned(znext), unsigned(backup_val), n_unobfuscated, p_unobfuscated, poison_str)
273 if unsigned(znext) == 0:
274 break
275 current = Cast(znext, 'void *')
276
277@static_var('elts_found',0)
278@static_var('last_poisoned',0)
279@lldb_command('showzfreelist')
280def ShowZfreeList(cmd_args=None):
281 """ Walk the freelist for a zone, printing out the primary and backup next pointers, the poisoning cookies, and the poisoning status of each element.
282 Usage: showzfreelist <zone> [iterations]
283
284 Will walk up to 50 elements by default, pass a limit in 'iterations' to override.
285 """
286 if not cmd_args:
287 print ShowZfreeList.__doc__
288 return
289 ShowZfreeList.elts_found = 0
290 ShowZfreeList.last_poisoned = 0
291
292 zone = kern.GetValueFromAddress(cmd_args[0], 'struct zone *')
293 zlimit = 50
294 if len(cmd_args) >= 2:
295 zlimit = ArgumentStringToInt(cmd_args[1])
296 ShowZfreeListHeader(zone)
297
298 if unsigned(zone.use_page_list) == 1:
299 if unsigned(zone.allows_foreign) == 1:
300 for free_page_meta in IterateQueue(zone.pages.any_free_foreign, 'struct zone_page_metadata *', 'pages'):
301 if ShowZfreeList.elts_found == zlimit:
302 break
303 zfirst = Cast(free_page_meta.elements, 'void *')
304 if unsigned(zfirst) != 0:
305 ShowZfreeListChain(zone, zfirst, zlimit)
306 for free_page_meta in IterateQueue(zone.pages.intermediate, 'struct zone_page_metadata *', 'pages'):
307 if ShowZfreeList.elts_found == zlimit:
308 break
309 zfirst = Cast(free_page_meta.elements, 'void *')
310 if unsigned(zfirst) != 0:
311 ShowZfreeListChain(zone, zfirst, zlimit)
312 for free_page_meta in IterateQueue(zone.pages.all_free, 'struct zone_page_metadata *', 'pages'):
313 if ShowZfreeList.elts_found == zlimit:
314 break
315 zfirst = Cast(free_page_meta.elements, 'void *')
316 if unsigned(zfirst) != 0:
317 ShowZfreeListChain(zone, zfirst, zlimit)
318 else:
319 zfirst = Cast(zone.free_elements, 'void *')
320 if unsigned(zfirst) != 0:
321 ShowZfreeListChain(zone, zfirst, zlimit)
322
323 if ShowZfreeList.elts_found == zlimit:
324 print "Stopped at {0: <d} elements!".format(zlimit)
325 else:
326 print "Found {0: <d} elements!".format(ShowZfreeList.elts_found)
327
328# EndMacro: showzfreelist
329
330# Macro: zstack
331
332@lldb_command('zstack')
333def Zstack(cmd_args=None):
334 """ Zone leak debugging: Print the stack trace of log element at <index>. If a <count> is supplied, it prints <count> log elements starting at <index>.
335 Usage: zstack <index> [<count>]
336
337 The suggested usage is to look at indexes below zcurrent and look for common stack traces.
338 The stack trace that occurs the most is probably the cause of the leak. Find the pc of the
339 function calling into zalloc and use the countpcs command to find out how often that pc occurs in the log.
340 The pc occuring in a high percentage of records is most likely the source of the leak.
341
342 The findoldest command is also useful for leak debugging since it identifies the oldest record
343 in the log, which may indicate the leaker.
344 """
345 if not cmd_args:
346 print Zstack.__doc__
347 return
348 if int(kern.globals.log_records) == 0:
349 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
350 return
351 if int(kern.globals.zlog_btlog) == 0:
352 print "Zone logging enabled, but zone has not been initialized yet."
353 return
354
355 count = 1
356 if len(cmd_args) >= 2:
357 count = ArgumentStringToInt(cmd_args[1])
358 zstack_index = unsigned(cmd_args[0])
359 while count and (zstack_index != 0xffffff):
360 zstack_record_offset = zstack_index * unsigned(kern.globals.zlog_btlog.btrecord_size)
361 zstack_record = kern.GetValueFromAddress(unsigned(kern.globals.zlog_btlog.btrecords) + zstack_record_offset, 'btlog_record_t *')
362 ShowZStackRecord(zstack_record, zstack_index)
363 zstack_index = zstack_record.next
364 count -= 1
365
366# EndMacro : zstack
367
368# Macro: findoldest
369
370@lldb_command('findoldest')
371def FindOldest(cmd_args=None):
372 """ Zone leak debugging: find and print the oldest record in the log.
373
374 Once it prints a stack trace, find the pc of the caller above all the zalloc, kalloc and
375 IOKit layers. Then use the countpcs command to see how often this caller has allocated
376 memory. A caller with a high percentage of records in the log is probably the leaker.
377 """
378 if int(kern.globals.log_records) == 0:
379 print FindOldest.__doc__
380 return
381 if int(kern.globals.zlog_btlog) == 0:
382 print "Zone logging enabled, but zone has not been initialized yet."
383 return
384 index = kern.globals.zlog_btlog.head
385 if unsigned(index) != 0xffffff:
386 print "Oldest record is at log index: {0: <d}".format(index)
387 Zstack([index])
388 else:
389 print "No Records Present"
390
391# EndMacro : findoldest
392
393# Macro: countpcs
394
395@lldb_command('countpcs')
396def Countpcs(cmd_args=None):
397 """ Zone leak debugging: search the log and print a count of all log entries that contain the given <pc>
398 in the stack trace.
399 Usage: countpcs <pc>
400
401 This is useful for verifying a suspected <pc> as being the source of
402 the leak. If a high percentage of the log entries contain the given <pc>, then it's most
403 likely the source of the leak. Note that this command can take several minutes to run.
404 """
405 if not cmd_args:
406 print Countpcs.__doc__
407 return
408 if int(kern.globals.log_records) == 0:
409 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
410 return
411 if int(kern.globals.zlog_btlog) == 0:
412 print "Zone logging enabled, but zone has not been initialized yet."
413 return
414
415 cpcs_index = unsigned(kern.globals.zlog_btlog.head)
416 target_pc = unsigned(kern.GetValueFromAddress(cmd_args[0], 'void *'))
417 found = 0
418 depth = unsigned(kern.globals.zlog_btlog.btrecord_btdepth)
419
420 while cpcs_index != 0xffffff:
421 cpcs_record_offset = cpcs_index * unsigned(kern.globals.zlog_btlog.btrecord_size)
422 cpcs_record = kern.GetValueFromAddress(unsigned(kern.globals.zlog_btlog.btrecords) + cpcs_record_offset, 'btlog_record_t *')
423 frame = 0
424 while frame < depth:
425 frame_pc = unsigned(cpcs_record.bt[frame])
426 if frame_pc == target_pc:
427 found += 1
428 break
429 frame += 1
430 cpcs_index = cpcs_record.next
431 print "Occured {0: <d} times in log ({1: <d}{2: <s} of records)".format(found, (found * 100)/unsigned(kern.globals.zlog_btlog.activecount), '%')
432
433# EndMacro: countpcs
434
435# Macro: findelem
436
437@lldb_command('findelem')
438def FindElem(cmd_args=None):
439 """ Zone corruption debugging: search the log and print out the stack traces for all log entries that
440 refer to the given zone element.
441 Usage: findelem <elem addr>
442
443 When the kernel panics due to a corrupted zone element, get the
444 element address and use this command. This will show you the stack traces of all logged zalloc and
445 zfree operations which tells you who touched the element in the recent past. This also makes
446 double-frees readily apparent.
447 """
448 if not cmd_args:
449 print FindElem.__doc__
450 return
451 if int(kern.globals.log_records) == 0:
452 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
453 return
454 if int(kern.globals.zlog_btlog) == 0:
455 print "Zone logging enabled, but zone has not been initialized yet."
456 return
457
458 target_element = unsigned(kern.GetValueFromAddress(cmd_args[0], 'void *'))
459 index = unsigned(kern.globals.zlog_btlog.head)
460 prev_op = -1
461
462 while index != 0xffffff:
463 findelem_record_offset = index * unsigned(kern.globals.zlog_btlog.btrecord_size)
464 findelem_record = kern.GetValueFromAddress(unsigned(kern.globals.zlog_btlog.btrecords) + findelem_record_offset, 'btlog_record_t *')
465 if unsigned(findelem_record.element) == target_element:
466 Zstack([index])
467 if int(findelem_record.operation) == prev_op:
468 print "{0: <s} DOUBLE OP! {1: <s}".format(('*' * 8), ('*' * 8))
469 prev_op = int(findelem_record.operation)
470 index = findelem_record.next
471
472# EndMacro: findelem
473
474# Macro: btlog_find
475
476@lldb_command('btlog_find', "A")
477def BtlogFind(cmd_args=None, cmd_options={}):
478 """ Search the btlog_t for entries corresponding to the given element.
479 Use -A flag to print all entries.
480 Usage: btlog_find <btlog_t> <element>
481 Usage: btlog_find <btlog_t> -A
482 Note: Backtraces will be in chronological order, with oldest entries aged out in FIFO order as needed.
483 """
484 if not cmd_args:
485 raise ArgumentError("Need a btlog_t parameter")
486 btlog = kern.GetValueFromAddress(cmd_args[0], 'btlog_t *')
487 printall = False
488 target_elem = 0xffffff
489
490 if "-A" in cmd_options:
491 printall = True
492 else:
493 if not printall and len(cmd_args) < 2:
494 raise ArgumentError("<element> is missing in args. Need a search pointer.")
495 target_elem = unsigned(kern.GetValueFromAddress(cmd_args[1], 'void *'))
496
497 index = unsigned(btlog.head)
498 progress = 0
499 record_size = unsigned(btlog.btrecord_size)
500 while index != 0xffffff:
501 record_offset = index * record_size
502 record = kern.GetValueFromAddress(unsigned(btlog.btrecords) + record_offset, 'btlog_record_t *')
503 if unsigned(record.element) == target_elem or printall:
504 print '{0: <s} OP {1: <d} {2: <#0x} {3: <s}\n'.format(('-' * 8), record.operation, target_elem, ('-' * 8))
505 ShowBtlogBacktrace(btlog.btrecord_btdepth, record)
506 index = record.next
507 progress += 1
508 if (progress % 1000) == 0: print '{0: <d} entries searched!\n'.format(progress)
509
510#EndMacro: btlog_find
511
512#Macro: showzalloc
513
514@lldb_command('showzalloc')
515def ShowZalloc(cmd_args=None):
516 """ Prints a zallocation from the zallocations array based off its index and prints the associated symbolicated backtrace.
517 Usage: showzalloc <index>
518 """
519 if not cmd_args:
520 print ShowZalloc.__doc__
521 return
522 if unsigned(kern.globals.zallocations) == 0:
523 print "zallocations array not initialized!"
524 return
525 zallocation = kern.globals.zallocations[ArgumentStringToInt(cmd_args[0])]
526 print zallocation
527 ShowZTrace([str(int(zallocation.za_trace_index))])
528
529#EndMacro: showzalloc
530
531#Macro: showztrace
532
533@lldb_command('showztrace')
534def ShowZTrace(cmd_args=None):
535 """ Prints the backtrace from the ztraces array at index
536 Usage: showztrace <trace index>
537 """
538 if not cmd_args:
539 print ShowZTrace.__doc__
540 return
541 if unsigned(kern.globals.ztraces) == 0:
542 print "ztraces array not initialized!"
543 return
544 ztrace_addr = kern.globals.ztraces[ArgumentStringToInt(cmd_args[0])]
545 print ztrace_addr
546 ShowZstackTraceHelper(ztrace_addr.zt_stack, ztrace_addr.zt_depth)
547
548#EndMacro: showztrace
549
550#Macro: showztraceaddr
551
552@lldb_command('showztraceaddr')
553def ShowZTraceAddr(cmd_args=None):
554 """ Prints the struct ztrace passed in.
555 Usage: showztraceaddr <trace address>
556 """
557 if not cmd_args:
558 print ShowZTraceAddr.__doc__
559 return
560 ztrace_ptr = kern.GetValueFromAddress(cmd_args[0], 'struct ztrace *')
561 print dereference(ztrace_ptr)
562 ShowZstackTraceHelper(ztrace_ptr.zt_stack, ztrace_ptr.zt_depth)
563
564#EndMacro: showztraceaddr
565
566#Macro: showzstacktrace
567
568@lldb_command('showzstacktrace')
569def ShowZstackTrace(cmd_args=None):
570 """ Routine to print a stacktrace stored by OSBacktrace.
571 Usage: showzstacktrace <saved stacktrace> [size]
572
573 size is optional, defaults to 15.
574 """
575 if not cmd_args:
576 print ShowZstackTrace.__doc__
577 return
578 void_ptr_type = gettype('void *')
579 void_double_ptr_type = void_ptr_type.GetPointerType()
580 trace = kern.GetValueFromAddress(cmd_args[0], void_double_ptr_type)
581 trace_size = 15
582 if len(cmd_args) >= 2:
583 trace_size = ArgumentStringToInt(cmd_args[1])
584 ShowZstackTraceHelper(trace, trace_size)
585
586#EndMacro: showzstacktrace
587
588def ShowZstackTraceHelper(stack, depth):
589 """ Helper routine for printing a zstack.
590 params:
591 stack: void *[] - An array of pointers representing the Zstack
592 depth: int - The depth of the ztrace stack
593 returns:
594 None
595 """
596 trace_current = 0
597 while trace_current < depth:
598 trace_addr = stack[trace_current]
599 symbol_arr = kern.SymbolicateFromAddress(unsigned(trace_addr))
600 if symbol_arr:
601 symbol_str = str(symbol_arr[0].addr)
602 else:
603 symbol_str = ''
604 print '{0: <#x} {1: <s}'.format(trace_addr, symbol_str)
605 trace_current += 1
606
607#Macro: showtopztrace
608
609@lldb_command('showtopztrace')
610def ShowTopZtrace(cmd_args=None):
611 """ Shows the ztrace with the biggest size.
612 (According to top_ztrace, not by iterating through the hash table)
613 """
614 top_trace = kern.globals.top_ztrace
615 print 'Index: {0: <d}'.format((unsigned(top_trace) - unsigned(kern.globals.ztraces)) / sizeof('struct ztrace'))
616 print dereference(top_trace)
617 ShowZstackTraceHelper(top_trace.zt_stack, top_trace.zt_depth)
618
619#EndMacro: showtopztrace
620
621#Macro: showzallocs
622
623@lldb_command('showzallocs')
624def ShowZallocs(cmd_args=None):
625 """ Prints all allocations in the zallocations table
626 """
627 if unsigned(kern.globals.zallocations) == 0:
628 print "zallocations array not initialized!"
629 return
630 print '{0: <5s} {1: <18s} {2: <5s} {3: <15s}'.format('INDEX','ADDRESS','TRACE','SIZE')
631 current_index = 0
632 max_zallocation = unsigned(kern.globals.zleak_alloc_buckets)
633 allocation_count = 0
634 while current_index < max_zallocation:
635 current_zalloc = kern.globals.zallocations[current_index]
636 if int(current_zalloc.za_element) != 0:
637 print '{0: <5d} {1: <#018x} {2: <5d} {3: <15d}'.format(current_index, current_zalloc.za_element, current_zalloc.za_trace_index, unsigned(current_zalloc.za_size))
638 allocation_count += 1
639 current_index += 1
640 print 'Total Allocations: {0: <d}'.format(allocation_count)
641
642#EndMacro: showzallocs
643
644#Macro: showzallocsfortrace
645
646@lldb_command('showzallocsfortrace')
647def ShowZallocsForTrace(cmd_args=None):
648 """ Prints all allocations pointing to the passed in trace's index into ztraces by looking through zallocations table
649 Usage: showzallocsfortrace <trace index>
650 """
651 if not cmd_args:
652 print ShowZallocsForTrace.__doc__
653 return
654 print '{0: <5s} {1: <18s} {2: <15s}'.format('INDEX','ADDRESS','SIZE')
655 target_index = ArgumentStringToInt(cmd_args[0])
656 current_index = 0
657 max_zallocation = unsigned(kern.globals.zleak_alloc_buckets)
658 allocation_count = 0
659 while current_index < max_zallocation:
660 current_zalloc = kern.globals.zallocations[current_index]
661 if unsigned(current_zalloc.za_element) != 0 and (unsigned(current_zalloc.za_trace_index) == unsigned(target_index)):
662 print '{0: <5d} {1: <#018x} {2: <6d}'.format(current_index, current_zalloc.za_element, current_zalloc.za_size)
663 allocation_count += 1
664 current_index += 1
665 print 'Total Allocations: {0: <d}'.format(allocation_count)
666
667#EndMacro: showzallocsfortrace
668
669#Macro: showztraces
670
671@lldb_command('showztraces')
672def ShowZTraces(cmd_args=None):
673 """ Prints all traces with size > 0
674 """
675 ShowZTracesAbove([0])
676
677#EndMacro: showztraces
678
679#Macro: showztracesabove
680
681@lldb_command('showztracesabove')
682def ShowZTracesAbove(cmd_args=None):
683 """ Prints all traces with size greater than X
684 Usage: showztracesabove <size>
685 """
686 if not cmd_args:
687 print ShowZTracesAbove.__doc__
688 return
689 print '{0: <5s} {1: <6s}'.format('INDEX','SIZE')
690 current_index = 0
691 ztrace_count = 0
692 max_ztrace = unsigned(kern.globals.zleak_trace_buckets)
693 while current_index < max_ztrace:
694 ztrace_current = kern.globals.ztraces[current_index]
695 if ztrace_current.zt_size > unsigned(cmd_args[0]):
696 print '{0: <5d} {1: <6d}'.format(current_index, int(ztrace_current.zt_size))
697 ztrace_count += 1
698 current_index += 1
699 print 'Total traces: {0: <d}'.format(ztrace_count)
700
701#EndMacro: showztracesabove
702
703#Macro: showztracehistogram
704
705@lldb_command('showztracehistogram')
706def ShowZtraceHistogram(cmd_args=None):
707 """ Prints the histogram of the ztrace table
708 """
709 print '{0: <5s} {1: <9s} {2: <10s}'.format('INDEX','HIT_COUNT','COLLISIONS')
710 current_index = 0
711 ztrace_count = 0
712 max_ztrace = unsigned(kern.globals.zleak_trace_buckets)
713 while current_index < max_ztrace:
714 ztrace_current = kern.globals.ztraces[current_index]
715 if ztrace_current.zt_hit_count != 0:
716 print '{0: <5d} {1: <9d} {2: <10d}'.format(current_index, ztrace_current.zt_hit_count, ztrace_current.zt_collisions)
717 ztrace_count += 1
718 current_index += 1
719 print 'Total traces: {0: <d}'.format(ztrace_count)
720
721#EndMacro: showztracehistogram
722
723#Macro: showzallochistogram
724
725@lldb_command('showzallochistogram')
726def ShowZallocHistogram(cmd_args=None):
727 """ Prints the histogram for the zalloc table
728 """
729 print '{0: <5s} {1: <9s}'.format('INDEX','HIT_COUNT')
730 current_index = 0
731 zallocation_count = 0
732 max_ztrace = unsigned(kern.globals.zleak_alloc_buckets)
733 while current_index < max_ztrace:
734 zallocation_current = kern.globals.zallocations[current_index]
735 if zallocation_current.za_hit_count != 0:
736 print '{0: <5d} {1: <9d}'.format(current_index, zallocation_current.za_hit_count)
737 zallocation_count += 1
738 current_index += 1
739 print 'Total Allocations: {0: <d}'.format(zallocation_count)
740
741#EndMacro: showzallochistogram
742
743#Macro: showzstats
744
745@lldb_command('showzstats')
746def ShowZstats(cmd_args=None):
747 """ Prints the zone leak detection stats
748 """
749 print 'z_alloc_collisions: {0: <d}, z_trace_collisions: {1: <d}'.format(unsigned(kern.globals.z_alloc_collisions), unsigned(kern.globals.z_trace_collisions))
750 print 'z_alloc_overwrites: {0: <d}, z_trace_overwrites: {1: <d}'.format(unsigned(kern.globals.z_alloc_overwrites), unsigned(kern.globals.z_trace_overwrites))
751 print 'z_alloc_recorded: {0: <d}, z_trace_recorded: {1: <d}'.format(unsigned(kern.globals.z_alloc_recorded), unsigned(kern.globals.z_trace_recorded))
752
753#EndMacro: showzstats
754
755def ShowBtlogBacktrace(depth, zstack_record):
756 """ Helper routine for printing a BT Log record backtrace stack.
757 params:
758 depth:int - The depth of the zstack record
759 zstack_record:btlog_record_t * - A BTLog record
760 returns:
761 None
762 """
763 out_str = ''
764 frame = 0
765 if not zstack_record:
766 print "Zstack record none!"
767 return
768 depth_val = unsigned(depth)
769 while frame < depth_val:
770 frame_pc = zstack_record.bt[frame]
771 if not frame_pc or int(frame_pc) == 0:
772 break
773 symbol_arr = kern.SymbolicateFromAddress(frame_pc)
774 if symbol_arr:
775 symbol_str = str(symbol_arr[0].addr)
776 else:
777 symbol_str = ''
778 out_str += "{0: <#0x} <{1: <s}>\n".format(frame_pc, symbol_str)
779 frame += 1
780 print out_str
781
782def ShowZStackRecord(zstack_record, zstack_index):
783 """ Helper routine for printing a single zstack record
784 params:
785 zstack_record:btlog_record_t * - A BTLog record
786 zstack_index:int - Index for the record in the BTLog table
787 returns:
788 None
789 """
790 out_str = ('-' * 8)
791 if zstack_record.operation == 1:
792 out_str += "ALLOC "
793 else:
794 out_str += "FREE "
795 out_str += "{0: <#0x} : Index {1: <d} {2: <s}\n".format(zstack_record.element, zstack_index, ('-' * 8))
796 print out_str
797 ShowBtlogBacktrace(kern.globals.zlog_btlog.btrecord_btdepth, zstack_record)
798
799# Macro: showioalloc
800
801@lldb_command('showioalloc')
802def ShowIOAllocations(cmd_args=None):
803 """ Show some accounting of memory allocated by IOKit allocators. See ioalloccount man page for details.
804 Routine to display a summary of memory accounting allocated by IOKit allocators.
805 """
806 print "Instance allocation = {0: <#0x} = {1: d}K".format(kern.globals.debug_ivars_size, (kern.globals.debug_ivars_size / 1024))
807 print "Container allocation = {0: <#0x} = {1: d}K".format(kern.globals.debug_container_malloc_size, (kern.globals.debug_container_malloc_size / 1024))
808 print "IOMalloc allocation = {0: <#0x} = {1: d}K".format(kern.globals.debug_iomalloc_size, (kern.globals.debug_iomalloc_size / 1024))
809 print "Container allocation = {0: <#0x} = {1: d}K".format(kern.globals.debug_iomallocpageable_size, (kern.globals.debug_iomallocpageable_size / 1024))
810
811
812# EndMacro: showioalloc
813
814
815
816
817# Macro: showtaskvme
818@lldb_command('showtaskvme')
819def ShowTaskVmeHelper(cmd_args=None):
820 """ Display a summary list of the specified vm_map's entries
821 Usage: showtaskvme <task address> (ex. showtaskvme 0x00ataskptr00 )
822 """
823 task = kern.GetValueFromAddress(cmd_args[0], 'task *')
824 ShowTaskVMEntries(task)
825
826@lldb_command('showallvme')
827def ShowAllVME(cmd_args=None):
828 """ Routine to print a summary listing of all the vm map entries
829 Go Through each task in system and show the vm info
830 """
831 for task in kern.tasks:
832 ShowTaskVMEntries(task)
833
834@lldb_command('showallvm')
835def ShowAllVM(cmd_args=None):
836 """ Routine to print a summary listing of all the vm maps
837 """
838 for task in kern.tasks:
839 print GetTaskSummary.header + ' ' + GetProcSummary.header
840 print GetTaskSummary(task) + ' ' + GetProcSummary(Cast(task.bsd_info, 'proc *'))
841 print GetVMMapSummary.header
842 print GetVMMapSummary(task.map)
843
844@lldb_command("showtaskvm")
845def ShowTaskVM(cmd_args=None):
846 """ Display info about the specified task's vm_map
847 syntax: (lldb) showtaskvm <task_ptr>
848 """
849 if not cmd_args:
850 print ShowTaskVM.__doc__
851 return False
852 task = kern.GetValueFromAddress(cmd_args[0], 'task *')
853 if not task:
854 print "Unknown arguments."
855 return False
856 print GetTaskSummary.header + ' ' + GetProcSummary.header
857 print GetTaskSummary(task) + ' ' + GetProcSummary(Cast(task.bsd_info, 'proc *'))
858 print GetVMMapSummary.header
859 print GetVMMapSummary(task.map)
860 return True
861
862@lldb_command('showallvmstats')
863def ShowAllVMStats(cmd_args=None):
864 """ Print a summary of vm statistics in a table format
865 """
866 vmstats = lambda:None
867 vmstats.wired_count = 0
868 vmstats.resident_count = 0
869 vmstats.resident_max = 0
870 vmstats.internal = 0
871 vmstats.external = 0
872 vmstats.reusable = 0
873 vmstats.compressed = 0
874 vmstats.compressed_peak = 0
875 vmstats.compressed_lifetime = 0
876 vmstats.error = ''
877
878 hdr_format = "{0: >10s} {1: <20s} {2: >6s} {3: >10s} {4: >10s} {5: >10s} {6: >10s} {7: >10s} {8: >10s} {9: >10s} {10: >10s} {11: >10s} {12: >10s} {13: >10s} {14:}"
879 print hdr_format.format('pid', 'command', '#ents', 'wired', 'vsize', 'rsize', 'NEW RSIZE', 'max rsize', 'internal', 'external', 'reusable', 'compressed', 'compressed', 'compressed', '')
880 print hdr_format.format('', '', '', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(current)', '(peak)', '(lifetime)', '')
881 entry_format = "{p.p_pid: >10d} {p.p_comm: <20s} {m.hdr.nentries: >6d} {s.wired_count: >10d} {vsize: >10d} {s.resident_count: >10d} {s.new_resident_count: >10d} {s.resident_max: >10d} {s.internal: >10d} {s.external: >10d} {s.reusable: >10d} {s.compressed: >10d} {s.compressed_peak: >10d} {s.compressed_lifetime: >10d} {s.error}"
882
883 for task in kern.tasks:
884 proc = Cast(task.bsd_info, 'proc *')
885 vmmap = Cast(task.map, '_vm_map *')
886 vmstats.error = ''
887 vmstats.wired_count = vmmap.pmap.stats.wired_count;
888 vmstats.resident_count = unsigned(vmmap.pmap.stats.resident_count);
889 vmstats.resident_max = vmmap.pmap.stats.resident_max;
890 vmstats.internal = unsigned(vmmap.pmap.stats.internal);
891 vmstats.external = unsigned(vmmap.pmap.stats.external);
892 vmstats.reusable = unsigned(vmmap.pmap.stats.reusable);
893 vmstats.compressed = unsigned(vmmap.pmap.stats.compressed);
894 vmstats.compressed_peak = unsigned(vmmap.pmap.stats.compressed_peak);
895 vmstats.compressed_lifetime = unsigned(vmmap.pmap.stats.compressed_lifetime);
896 vmstats.new_resident_count = vmstats.internal + vmstats.external
897
898 if vmstats.internal < 0:
899 vmstats.error += '*'
900 if vmstats.external < 0:
901 vmstats.error += '*'
902 if vmstats.reusable < 0:
903 vmstats.error += '*'
904 if vmstats.compressed < 0:
905 vmstats.error += '*'
906 if vmstats.compressed_peak < 0:
907 vmstats.error += '*'
908 if vmstats.compressed_lifetime < 0:
909 vmstats.error += '*'
910 if vmstats.new_resident_count +vmstats.reusable != vmstats.resident_count:
911 vmstats.error += '*'
912
913 print entry_format.format(p=proc, m=vmmap, vsize=(unsigned(vmmap.size) >> 12), t=task, s=vmstats)
914
915
916def ShowTaskVMEntries(task):
917 """ Routine to print out a summary listing of all the entries in a vm_map
918 params:
919 task - core.value : a object of type 'task *'
920 returns:
921 None
922 """
923 print "vm_map entries for task " + hex(task)
924 print GetTaskSummary.header
925 print GetTaskSummary(task)
926 if not task.map:
927 print "Task {0: <#020x} has map = 0x0"
928 return None
929 print GetVMMapSummary.header
930 print GetVMMapSummary(task.map)
931 vme_list_head = task.map.hdr.links
932 vme_ptr_type = GetType('vm_map_entry *')
933 print GetVMEntrySummary.header
934 for vme in IterateQueue(vme_list_head, vme_ptr_type, "links"):
935 print GetVMEntrySummary(vme)
936 return None
937
938@lldb_command("showmap")
939def ShowMap(cmd_args=None):
940 """ Routine to print out info about the specified vm_map
941 usage: showmap <vm_map>
942 """
943 if cmd_args == None or len(cmd_args) < 1:
944 print "Invalid argument.", ShowMap.__doc__
945 return
946 map_val = kern.GetValueFromAddress(cmd_args[0], 'vm_map_t')
947 print GetVMMapSummary.header
948 print GetVMMapSummary(map_val)
949
950@lldb_command("showmapvme")
951def ShowMapVME(cmd_args=None):
952 """Routine to print out info about the specified vm_map and its vm entries
953 usage: showmapvme <vm_map>
954 """
955 if cmd_args == None or len(cmd_args) < 1:
956 print "Invalid argument.", ShowMap.__doc__
957 return
958 map_val = kern.GetValueFromAddress(cmd_args[0], 'vm_map_t')
959 print GetVMMapSummary.header
960 print GetVMMapSummary(map_val)
961 vme_list_head = map_val.hdr.links
962 vme_ptr_type = GetType('vm_map_entry *')
963 print GetVMEntrySummary.header
964 for vme in IterateQueue(vme_list_head, vme_ptr_type, "links"):
965 print GetVMEntrySummary(vme)
966 return None
967
968@lldb_type_summary(['_vm_map *', 'vm_map_t'])
969@header("{0: <20s} {1: <20s} {2: <20s} {3: >5s} {4: >5s} {5: <20s} {6: <20s}".format("vm_map", "pmap", "vm_size", "#ents", "rpage", "hint", "first_free"))
970def GetVMMapSummary(vmmap):
971 """ Display interesting bits from vm_map struct """
972 out_string = ""
973 format_string = "{0: <#020x} {1: <#020x} {2: <#020x} {3: >5d} {4: >5d} {5: <#020x} {6: <#020x}"
974 vm_size = uint64_t(vmmap.size).value
975 resident_pages = 0
976 if vmmap.pmap != 0: resident_pages = int(vmmap.pmap.stats.resident_count)
977 out_string += format_string.format(vmmap, vmmap.pmap, vm_size, vmmap.hdr.nentries, resident_pages, vmmap.hint, vmmap.first_free)
978 return out_string
979
980@lldb_type_summary(['vm_map_entry'])
981@header("{0: <20s} {1: <20s} {2: <5s} {3: >7s} {4: <20s} {5: <20s}".format("entry", "start", "prot", "#page", "object", "offset"))
982def GetVMEntrySummary(vme):
983 """ Display vm entry specific information. """
984 out_string = ""
985 format_string = "{0: <#020x} {1: <#20x} {2: <1x}{3: <1x}{4: <3s} {5: >7d} {6: <#020x} {7: <#020x}"
986 vme_protection = int(vme.protection)
987 vme_max_protection = int(vme.max_protection)
988 vme_extra_info_str ="SC-Ds"[int(vme.inheritance)]
989 if int(vme.is_sub_map) != 0 :
990 vme_extra_info_str +="s"
991 elif int(vme.needs_copy) != 0 :
992 vme_extra_info_str +="n"
993 num_pages = (unsigned(vme.links.end) - unsigned(vme.links.start)) >> 12
994 out_string += format_string.format(vme, vme.links.start, vme_protection, vme_max_protection, vme_extra_info_str, num_pages, vme.object.vm_object, vme.offset)
995 return out_string
996
997# EndMacro: showtaskvme
998@lldb_command('showmapwired')
999def ShowMapWired(cmd_args=None):
1000 """ Routine to print out a summary listing of all the entries with wired pages in a vm_map
1001 """
1002 if cmd_args == None or len(cmd_args) < 1:
1003 print "Invalid argument", ShowMapWired.__doc__
1004 return
1005 map_val = kern.GetValueFromAddress(cmd_args[0], 'vm_map_t')
1006
1007
1008@lldb_type_summary(['kmod_info_t *'])
1009@header("{0: <20s} {1: <20s} {2: <20s} {3: >3s} {4: >5s} {5: >20s} {6: <30s}".format('kmod_info', 'address', 'size', 'id', 'refs', 'version', 'name'))
1010def GetKextSummary(kmod):
1011 """ returns a string representation of kext information
1012 """
1013 out_string = ""
1014 format_string = "{0: <#020x} {1: <#020x} {2: <#020x} {3: >3d} {4: >5d} {5: >20s} {6: <30s}"
1015 out_string += format_string.format(kmod, kmod.address, kmod.size, kmod.id, kmod.reference_count, kmod.version, kmod.name)
1016 return out_string
1017
1018@lldb_type_summary(['uuid_t'])
1019@header("")
1020def GetUUIDSummary(uuid):
1021 """ returns a string representation like CA50DA4C-CA10-3246-B8DC-93542489AA26
1022 """
1023 arr = Cast(addressof(uuid), 'uint8_t *')
1024 data = []
1025 for i in range(16):
1026 data.append(int(arr[i]))
1027 return "{a[0]:02X}{a[1]:02X}{a[2]:02X}{a[3]:02X}-{a[4]:02X}{a[5]:02X}-{a[6]:02X}{a[7]:02X}-{a[8]:02X}{a[9]:02X}-{a[10]:02X}{a[11]:02X}{a[12]:02X}{a[13]:02X}{a[14]:02X}{a[15]:02X}".format(a=data)
1028
1029@lldb_command('showallkmods')
1030def ShowAllKexts(cmd_args=None):
1031 """Display a summary listing of all loaded kexts (alias: showallkmods)
1032 """
1033 kmod_val = kern.globals.kmod
1034 print "{: <36s} ".format("UUID") + GetKextSummary.header
1035 kextuuidinfo = GetKextLoadInformation()
1036 for kval in IterateLinkedList(kmod_val, 'next'):
1037 uuid = "........-....-....-....-............"
1038 kaddr = unsigned(kval.address)
1039 for l in kextuuidinfo :
1040 if kaddr == int(l[1],16):
1041 uuid = l[0]
1042 break
1043 print uuid + " " + GetKextSummary(kval)
1044
1045def GetKextLoadInformation(addr=0):
1046 """ Extract the kext uuid and load address information from the kernel data structure.
1047 params:
1048 addr - int - optional integer that is the address to search for.
1049 returns:
1050 [] - array with each entry of format ( 'UUID', 'Hex Load Address')
1051 """
1052 # because of <rdar://problem/12683084>, we can't find summaries directly
1053 #addr = hex(addressof(kern.globals.gLoadedKextSummaries.summaries))
1054 baseaddr = unsigned(kern.globals.gLoadedKextSummaries) + 0x10
1055 summaries_begin = kern.GetValueFromAddress(baseaddr, 'OSKextLoadedKextSummary *')
1056 total_summaries = int(kern.globals.gLoadedKextSummaries.numSummaries)
1057 kext_version = int(kern.globals.gLoadedKextSummaries.version)
1058 entry_size = 64 + 16 + 8 + 8 + 8 + 4 + 4
1059 if kext_version >= 2 :
1060 entry_size = int(kern.globals.gLoadedKextSummaries.entry_size)
1061 retval = []
1062 for i in range(total_summaries):
1063 tmpaddress = unsigned(summaries_begin) + (i * entry_size)
1064 current_kext = kern.GetValueFromAddress(tmpaddress, 'OSKextLoadedKextSummary *')
1065 if addr != 0 :
1066 if addr == unsigned(current_kext.address):
1067 retval.append((GetUUIDSummary(current_kext.uuid) , hex(current_kext.address), str(current_kext.name) ))
1068 else:
1069 retval.append((GetUUIDSummary(current_kext.uuid) , hex(current_kext.address), str(current_kext.name) ))
1070
1071 return retval
1072
1073lldb_alias('showallkexts', 'showallkmods')
1074
1075def GetOSKextVersion(version_num):
1076 """ returns a string of format 1.2.3x from the version_num
1077 params: version_num - int
1078 return: str
1079 """
1080 if version_num == -1 :
1081 return "invalid"
1082 (MAJ_MULT, MIN_MULT, REV_MULT,STAGE_MULT) = (100000000, 1000000, 10000, 1000)
1083 version = version_num
1084
1085 vers_major = version / MAJ_MULT
1086 version = version - (vers_major * MAJ_MULT)
1087
1088 vers_minor = version / MIN_MULT
1089 version = version - (vers_minor * MIN_MULT)
1090
1091 vers_revision = version / REV_MULT
1092 version = version - (vers_revision * REV_MULT)
1093
1094 vers_stage = version / STAGE_MULT
1095 version = version - (vers_stage * STAGE_MULT)
1096
1097 vers_stage_level = version
1098
1099 out_str = "%d.%d" % (vers_major, vers_minor)
1100 if vers_revision > 0: out_str += ".%d" % vers_revision
1101 if vers_stage == 1 : out_str += "d%d" % vers_stage_level
1102 if vers_stage == 3 : out_str += "a%d" % vers_stage_level
1103 if vers_stage == 5 : out_str += "b%d" % vers_stage_level
1104 if vers_stage == 6 : out_str += "fc%d" % vers_stage_level
1105
1106 return out_str
1107
1108@lldb_command('showallknownkmods')
1109def ShowAllKnownKexts(cmd_args=None):
1110 """ Display a summary listing of all kexts known in the system.
1111 This is particularly useful to find if some kext was unloaded before this crash'ed state.
1112 """
1113 kext_count = int(kern.globals.sKextsByID.count)
1114 index = 0
1115 kext_dictionary = kern.globals.sKextsByID.dictionary
1116 print "%d kexts in sKextsByID:" % kext_count
1117 print "{0: <20s} {1: <20s} {2: >5s} {3: >20s} {4: <30s}".format('OSKEXT *', 'load_addr', 'id', 'version', 'name')
1118 format_string = "{0: <#020x} {1: <20s} {2: >5s} {3: >20s} {4: <30s}"
1119
1120 while index < kext_count:
1121 kext_dict = GetObjectAtIndexFromArray(kext_dictionary, index)
1122 kext_name = str(kext_dict.key.string)
1123 osk = Cast(kext_dict.value, 'OSKext *')
1124 if int(osk.flags.loaded) :
1125 load_addr = "{0: <#020x}".format(osk.kmod_info)
1126 id = "{0: >5d}".format(osk.loadTag)
1127 else:
1128 load_addr = "------"
1129 id = "--"
1130 version_num = unsigned(osk.version)
1131 version = GetOSKextVersion(version_num)
1132 print format_string.format(osk, load_addr, id, version, kext_name)
1133 index += 1
1134
1135 return
1136
1137@lldb_command('showkmodaddr')
1138def ShowKmodAddr(cmd_args=[]):
1139 """ Given an address, print the offset and name for the kmod containing it
1140 Syntax: (lldb) showkmodaddr <addr>
1141 """
1142 if len(cmd_args) < 1:
1143 raise ArgumentError("Insufficient arguments")
1144
1145 addr = ArgumentStringToInt(cmd_args[0])
1146 kmod_val = kern.globals.kmod
1147 for kval in IterateLinkedList(kmod_val, 'next'):
1148 if addr >= unsigned(kval.address) and addr <= (unsigned(kval.address) + unsigned(kval.size)):
1149 print GetKextSummary.header
1150 print GetKextSummary(kval) + " offset = {0: #0x}".format((addr - unsigned(kval.address)))
1151 return True
1152 return False
1153
1154@lldb_command('addkext','F:N:')
1155def AddKextSyms(cmd_args=[], cmd_options={}):
1156 """ Add kext symbols into lldb.
1157 This command finds symbols for a uuid and load the required executable
1158 Usage:
1159 addkext <uuid> : Load one kext based on uuid. eg. (lldb)addkext 4DD2344C0-4A81-3EAB-BDCF-FEAFED9EB73E
1160 addkext -F <abs/path/to/executable> <load_address> : Load kext executable at specified load address
1161 addkext -N <name> : Load one kext that matches the name provided. eg. (lldb) addkext -N corecrypto
1162 addkext all : Will load all the kext symbols - SLOW
1163 """
1164
1165
1166 if "-F" in cmd_options:
1167 exec_path = cmd_options["-F"]
1168 exec_full_path = ResolveFSPath(exec_path)
1169 if not os.path.exists(exec_full_path):
1170 raise ArgumentError("Unable to resolve {:s}".format(exec_path))
1171
1172 if not os.path.isfile(exec_full_path):
1173 raise ArgumentError("Path is {:s} not a filepath. \nPlease check that path points to executable.\
1174\nFor ex. path/to/Symbols/IOUSBFamily.kext/Contents/PlugIns/AppleUSBHub.kext/Contents/MacOS/AppleUSBHub.\
1175\nNote: LLDB does not support adding kext based on directory paths like gdb used to.".format(exec_path))
1176 if not os.access(exec_full_path, os.X_OK):
1177 raise ArgumentError("Path is {:s} not an executable file".format(exec_path))
1178
1179 slide_value = None
1180 if cmd_args:
1181 slide_value = cmd_args[0]
1182 debuglog("loading slide value from user input %s" % cmd_args[0])
1183
1184 filespec = lldb.SBFileSpec(exec_full_path, False)
1185 print "target modules add %s" % exec_full_path
1186 print lldb_run_command("target modules add %s" % exec_full_path)
1187 loaded_module = LazyTarget.GetTarget().FindModule(filespec)
1188 if loaded_module.IsValid():
1189 uuid_str = loaded_module.GetUUIDString()
1190 debuglog("added module %s with uuid %s" % (exec_full_path, uuid_str))
1191 if slide_value is None:
1192 all_kexts_info = GetKextLoadInformation()
1193 for k in all_kexts_info:
1194 debuglog(k[0])
1195 if k[0].lower() == uuid_str.lower():
1196 slide_value = k[1]
1197 debuglog("found the slide %s for uuid %s" % (k[1], k[0]))
1198
1199 if slide_value is None:
1200 raise ArgumentError("Unable to find load address for module described at %s " % exec_full_path)
1201 load_cmd = "target modules load --file %s --slide %s" % (exec_full_path, str(slide_value))
1202 print load_cmd
1203 print lldb_run_command(load_cmd)
1204 kern.symbolicator = None
1205 return True
1206
1207 all_kexts_info = GetKextLoadInformation()
1208
1209 if "-N" in cmd_options:
1210 kext_name = cmd_options["-N"]
1211 kext_name_matches = GetLongestMatchOption(kext_name, [str(x[2]) for x in all_kexts_info], True)
1212 if len(kext_name_matches) != 1:
1213 print "Ambiguous match for name: {:s}".format(kext_name)
1214 if len(kext_name_matches) > 0:
1215 print "Options are:\n\t" + "\n\t".join(kext_name_matches)
1216 return
1217 debuglog("matched the kext to name %s and uuid %s" % (kext_name_matches[0], kext_name))
1218 for x in all_kexts_info:
1219 if kext_name_matches[0] == x[2]:
1220 cur_uuid = x[0].lower()
1221 print "Fetching dSYM for {:s}".format(cur_uuid)
1222 info = dsymForUUID(cur_uuid)
1223 if info and 'DBGSymbolRichExecutable' in info:
1224 print "Adding dSYM ({0:s}) for {1:s}".format(cur_uuid, info['DBGSymbolRichExecutable'])
1225 addDSYM(cur_uuid, info)
1226 loadDSYM(cur_uuid, int(x[1],16))
1227 else:
1228 print "Failed to get symbol info for {:s}".format(cur_uuid)
1229 break
1230 kern.symbolicator = None
1231 return
1232
1233 if len(cmd_args) < 1:
1234 raise ArgumentError("No arguments specified.")
1235
1236 uuid = cmd_args[0].lower()
1237
1238 load_all_kexts = False
1239 if uuid == "all":
1240 load_all_kexts = True
1241
1242 if not load_all_kexts and len(uuid_regex.findall(uuid)) == 0:
1243 raise ArgumentError("Unknown argument {:s}".format(uuid))
1244
1245 for k_info in all_kexts_info:
1246 cur_uuid = k_info[0].lower()
1247 if load_all_kexts or (uuid == cur_uuid):
1248 print "Fetching dSYM for %s" % cur_uuid
1249 info = dsymForUUID(cur_uuid)
1250 if info and 'DBGSymbolRichExecutable' in info:
1251 print "Adding dSYM (%s) for %s" % (cur_uuid, info['DBGSymbolRichExecutable'])
1252 addDSYM(cur_uuid, info)
1253 loadDSYM(cur_uuid, int(k_info[1],16))
1254 else:
1255 print "Failed to get symbol info for %s" % cur_uuid
1256 #end of for loop
1257 kern.symbolicator = None
1258 return True
1259
1260
1261
1262lldb_alias('showkmod', 'showkmodaddr')
1263lldb_alias('showkext', 'showkmodaddr')
1264lldb_alias('showkextaddr', 'showkmodaddr')
1265
1266@lldb_type_summary(['mount *'])
1267@header("{0: <20s} {1: <20s} {2: <20s} {3: <12s} {4: <12s} {5: <12s} {6: >6s} {7: <30s} {8: <35s}".format('volume(mp)', 'mnt_data', 'mnt_devvp', 'flag', 'kern_flag', 'lflag', 'type', 'mnton', 'mntfrom'))
1268def GetMountSummary(mount):
1269 """ Display a summary of mount on the system
1270 """
1271 out_string = ("{mnt: <#020x} {mnt.mnt_data: <#020x} {mnt.mnt_devvp: <#020x} {mnt.mnt_flag: <#012x} " +
1272 "{mnt.mnt_kern_flag: <#012x} {mnt.mnt_lflag: <#012x} {vfs.f_fstypename: >6s} " +
1273 "{vfs.f_mntonname: <30s} {vfs.f_mntfromname: <35s}").format(mnt=mount, vfs=mount.mnt_vfsstat)
1274 return out_string
1275
1276@lldb_command('showallmounts')
1277def ShowAllMounts(cmd_args=None):
1278 """ Print all mount points
1279 """
1280 mntlist = kern.globals.mountlist
1281 print GetMountSummary.header
1282 for mnt in IterateTAILQ_HEAD(mntlist, 'mnt_list'):
1283 print GetMountSummary(mnt)
1284 return
1285
1286lldb_alias('ShowAllVols', 'showallmounts')
1287
1288@lldb_command('systemlog')
1289def ShowSystemLog(cmd_args=None):
1290 """ Display the kernel's printf ring buffer """
1291 msgbufp = kern.globals.msgbufp
1292 msg_size = int(msgbufp.msg_size)
1293 msg_bufx = int(msgbufp.msg_bufx)
1294 msg_bufr = int(msgbufp.msg_bufr)
1295 msg_bufc = msgbufp.msg_bufc
1296 msg_bufc_data = msg_bufc.GetSBValue().GetPointeeData(0, msg_size)
1297
1298 # the buffer is circular; start at the write pointer to end,
1299 # then from beginning to write pointer
1300 line = ''
1301 err = lldb.SBError()
1302 for i in range(msg_bufx, msg_size) + range(0, msg_bufx) :
1303 err.Clear()
1304 cbyte = msg_bufc_data.GetUnsignedInt8(err, i)
1305 if not err.Success() :
1306 raise ValueError("Failed to read character at offset " + i + ": " + err.GetCString())
1307 c = chr(cbyte)
1308 if c == '\0' :
1309 continue
1310 elif c == '\n' :
1311 print line
1312 line = ''
1313 else :
1314 line += c
1315
1316 if len(line) > 0 :
1317 print line
1318
1319 return
1320
1321@static_var('output','')
1322def _GetVnodePathName(vnode, vnodename):
1323 """ Internal function to get vnode path string from vnode structure.
1324 params:
1325 vnode - core.value
1326 vnodename - str
1327 returns Nothing. The output will be stored in the static variable.
1328 """
1329 if not vnode:
1330 return
1331 if int(vnode.v_flag) & 0x1 and int(hex(vnode.v_mount), 16) !=0:
1332 if int(vnode.v_mount.mnt_vnodecovered):
1333 _GetVnodePathName(vnode.v_mount.mnt_vnodecovered, str(vnode.v_mount.mnt_vnodecovered.v_name) )
1334 else:
1335 _GetVnodePathName(vnode.v_parent, str(vnode.v_parent.v_name))
1336 _GetVnodePathName.output += "/%s" % vnodename
1337
1338def GetVnodePath(vnode):
1339 """ Get string representation of the vnode
1340 params: vnodeval - value representing vnode * in the kernel
1341 return: str - of format /path/to/something
1342 """
1343 out_str = ''
1344 if vnode:
1345 if (int(vnode.v_flag) & 0x000001) and int(hex(vnode.v_mount), 16) != 0 and (int(vnode.v_mount.mnt_flag) & 0x00004000) :
1346 out_str += "/"
1347 else:
1348 _GetVnodePathName.output = ''
1349 if abs(vnode.v_name) != 0:
1350 _GetVnodePathName(vnode, str(vnode.v_name))
1351 out_str += _GetVnodePathName.output
1352 else:
1353 out_str += 'v_name = NULL'
1354 _GetVnodePathName.output = ''
1355 return out_str
1356
1357
1358@lldb_command('showvnodepath')
1359def ShowVnodePath(cmd_args=None):
1360 """ Prints the path for a vnode
1361 usage: showvnodepath <vnode>
1362 """
1363 if cmd_args != None and len(cmd_args) > 0 :
1364 vnode_val = kern.GetValueFromAddress(cmd_args[0], 'vnode *')
1365 if vnode_val:
1366 print GetVnodePath(vnode_val)
1367 return
1368
1369# Macro: showvnodedev
1370def GetVnodeDevInfo(vnode):
1371 """ Internal function to get information from the device type vnodes
1372 params: vnode - value representing struct vnode *
1373 return: str - formatted output information for block and char vnode types passed as param
1374 """
1375 vnodedev_output = ""
1376 vblk_type = GetEnumValue('vtype::VBLK')
1377 vchr_type = GetEnumValue('vtype::VCHR')
1378 if (vnode.v_type == vblk_type) or (vnode.v_type == vchr_type):
1379 devnode = Cast(vnode.v_data, 'devnode_t *')
1380 devnode_dev = devnode.dn_typeinfo.dev
1381 devnode_major = (devnode_dev >> 24) & 0xff
1382 devnode_minor = devnode_dev & 0x00ffffff
1383
1384 # boilerplate device information for a vnode
1385 vnodedev_output += "Device Info:\n\t vnode:\t\t{:#x}".format(vnode)
1386 vnodedev_output += "\n\t type:\t\t"
1387 if (vnode.v_type == vblk_type):
1388 vnodedev_output += "VBLK"
1389 if (vnode.v_type == vchr_type):
1390 vnodedev_output += "VCHR"
1391 vnodedev_output += "\n\t name:\t\t{:<s}".format(vnode.v_name)
1392 vnodedev_output += "\n\t major, minor:\t{:d},{:d}".format(devnode_major, devnode_minor)
1393 vnodedev_output += "\n\t mode\t\t0{:o}".format(unsigned(devnode.dn_mode))
1394 vnodedev_output += "\n\t owner (u,g):\t{:d} {:d}".format(devnode.dn_uid, devnode.dn_gid)
1395
1396 # decode device specific data
1397 vnodedev_output += "\nDevice Specific Information:\t"
1398 if (vnode.v_type == vblk_type):
1399 vnodedev_output += "Sorry, I do not know how to decode block devices yet!"
1400 vnodedev_output += "\nMaybe you can write me!"
1401
1402 if (vnode.v_type == vchr_type):
1403 # Device information; this is scanty
1404 # range check
1405 if (devnode_major > 42) or (devnode_major < 0):
1406 vnodedev_output += "Invalid major #\n"
1407 # static assignments in conf
1408 elif (devnode_major == 0):
1409 vnodedev_output += "Console mux device\n"
1410 elif (devnode_major == 2):
1411 vnodedev_output += "Current tty alias\n"
1412 elif (devnode_major == 3):
1413 vnodedev_output += "NULL device\n"
1414 elif (devnode_major == 4):
1415 vnodedev_output += "Old pty slave\n"
1416 elif (devnode_major == 5):
1417 vnodedev_output += "Old pty master\n"
1418 elif (devnode_major == 6):
1419 vnodedev_output += "Kernel log\n"
1420 elif (devnode_major == 12):
1421 vnodedev_output += "Memory devices\n"
1422 # Statically linked dynamic assignments
1423 elif unsigned(kern.globals.cdevsw[devnode_major].d_open) == unsigned(kern.GetLoadAddressForSymbol('ptmx_open')):
1424 vnodedev_output += "Cloning pty master not done\n"
1425 #GetVnodeDevCpty(devnode_major, devnode_minor)
1426 elif unsigned(kern.globals.cdevsw[devnode_major].d_open) == unsigned(kern.GetLoadAddressForSymbol('ptsd_open')):
1427 vnodedev_output += "Cloning pty slave not done\n"
1428 #GetVnodeDevCpty(devnode_major, devnode_minor)
1429 else:
1430 vnodedev_output += "RESERVED SLOT\n"
1431 else:
1432 vnodedev_output += "{:#x} is not a device".format(vnode)
1433 return vnodedev_output
1434
1435@lldb_command('showvnodedev')
1436def ShowVnodeDev(cmd_args=None):
1437 """ Routine to display details of all vnodes of block and character device types
1438 Usage: showvnodedev <address of vnode>
1439 """
1440 if not cmd_args:
1441 print "No arguments passed"
1442 print ShowVnodeDev.__doc__
1443 return False
1444 vnode_val = kern.GetValueFromAddress(cmd_args[0], 'vnode *')
1445 if not vnode_val:
1446 print "unknown arguments:", str(cmd_args)
1447 return False
1448 print GetVnodeDevInfo(vnode_val)
1449
1450# EndMacro: showvnodedev
1451
1452# Macro: showvnodelocks
1453def GetVnodeLock(lockf):
1454 """ Internal function to get information from the given advisory lock
1455 params: lockf - value representing v_lockf member in struct vnode *
1456 return: str - formatted output information for the advisory lock
1457 """
1458 vnode_lock_output = ''
1459 lockf_flags = lockf.lf_flags
1460 lockf_type = lockf.lf_type
1461 if lockf_flags & 0x20:
1462 vnode_lock_output += ("{: <8s}").format('flock')
1463 if lockf_flags & 0x40:
1464 vnode_lock_output += ("{: <8s}").format('posix')
1465 if lockf_flags & 0x80:
1466 vnode_lock_output += ("{: <8s}").format('prov')
1467 if lockf_flags & 0x10:
1468 vnode_lock_output += ("{: <4s}").format('W')
1469 else:
1470 vnode_lock_output += ("{: <4s}").format('.')
1471
1472 # POSIX file vs advisory range locks
1473 if lockf_flags & 0x40:
1474 lockf_proc = Cast(lockf.lf_id, 'proc *')
1475 vnode_lock_output += ("PID {: <18d}").format(lockf_proc.p_pid)
1476 else:
1477 vnode_lock_output += ("ID {: <#019x}").format(int(lockf.lf_id))
1478
1479 # lock type
1480 if lockf_type == 1:
1481 vnode_lock_output += ("{: <12s}").format('shared')
1482 else:
1483 if lockf_type == 3:
1484 vnode_lock_output += ("{: <12s}").format('exclusive')
1485 else:
1486 if lockf_type == 2:
1487 vnode_lock_output += ("{: <12s}").format('unlock')
1488 else:
1489 vnode_lock_output += ("{: <12s}").format('unknown')
1490
1491 # start and stop values
1492 vnode_lock_output += ("{: #018x} ..").format(lockf.lf_start)
1493 vnode_lock_output += ("{: #018x}\n").format(lockf.lf_end)
1494 return vnode_lock_output
1495
1496@header("{0: <3s} {1: <7s} {2: <3s} {3: <21s} {4: <11s} {5: ^19s} {6: ^17s}".format('*', 'type', 'W', 'held by', 'lock type', 'start', 'end'))
1497def GetVnodeLocksSummary(vnode):
1498 """ Internal function to get summary of advisory locks for the given vnode
1499 params: vnode - value representing the vnode object
1500 return: str - formatted output information for the summary of advisory locks
1501 """
1502 out_str = ''
1503 if vnode:
1504 lockf_list = vnode.v_lockf
1505 for lockf_itr in IterateLinkedList(lockf_list, 'lf_next'):
1506 out_str += ("{: <4s}").format('H')
1507 out_str += GetVnodeLock(lockf_itr)
1508 lockf_blocker = lockf_itr.lf_blkhd.tqh_first
1509 while lockf_blocker:
1510 out_str += ("{: <4s}").format('>')
1511 out_str += GetVnodeLock(lockf_blocker)
1512 lockf_blocker = lockf_blocker.lf_block.tqe_next
1513 return out_str
1514
1515@lldb_command('showvnodelocks')
1516def ShowVnodeLocks(cmd_args=None):
1517 """ Routine to display list of advisory record locks for the given vnode address
1518 Usage: showvnodelocks <address of vnode>
1519 """
1520 if not cmd_args:
1521 print "No arguments passed"
1522 print ShowVnodeLocks.__doc__
1523 return False
1524 vnode_val = kern.GetValueFromAddress(cmd_args[0], 'vnode *')
1525 if not vnode_val:
1526 print "unknown arguments:", str(cmd_args)
1527 return False
1528 print GetVnodeLocksSummary.header
1529 print GetVnodeLocksSummary(vnode_val)
1530
1531# EndMacro: showvnodelocks
1532
1533# Macro: showproclocks
1534
1535@lldb_command('showproclocks')
1536def ShowProcLocks(cmd_args=None):
1537 """ Routine to display list of advisory record locks for the given process
1538 Usage: showproclocks <address of proc>
1539 """
1540 if not cmd_args:
1541 print "No arguments passed"
1542 print ShowProcLocks.__doc__
1543 return False
1544 proc = kern.GetValueFromAddress(cmd_args[0], 'proc *')
1545 if not proc:
1546 print "unknown arguments:", str(cmd_args)
1547 return False
1548 out_str = ''
1549 proc_filedesc = proc.p_fd
1550 fd_lastfile = proc_filedesc.fd_lastfile
1551 fd_ofiles = proc_filedesc.fd_ofiles
1552 count = 0
1553 seen = 0
1554 while count <= fd_lastfile:
1555 if fd_ofiles[count]:
1556 fglob = fd_ofiles[count].f_fglob
1557 fo_type = fglob.fg_ops.fo_type
1558 if fo_type == 1:
1559 fg_data = fglob.fg_data
1560 fg_vnode = Cast(fg_data, 'vnode *')
1561 name = fg_vnode.v_name
1562 lockf_itr = fg_vnode.v_lockf
1563 if lockf_itr:
1564 if not seen:
1565 print GetVnodeLocksSummary.header
1566 seen = seen + 1
1567 out_str += ("\n( fd {:d}, name ").format(count)
1568 if not name:
1569 out_str += "(null) )\n"
1570 else:
1571 out_str += "{:s} )\n".format(name)
1572 print out_str
1573 print GetVnodeLocksSummary(fg_vnode)
1574 count = count + 1
1575 print "\n{0: d} total locks for {1: #018x}".format(seen, proc)
1576
1577# EndMacro: showproclocks
1578
1579@lldb_type_summary(['vnode_t', 'vnode *'])
1580@header("{0: <20s} {1: >8s} {2: >8s} {3: <20s} {4: <6s} {5: <20s} {6: <6s} {7: <35s}".format('vnode', 'usecount', 'iocount', 'v_data', 'vtype', 'parent', 'mapped', 'name'))
1581def GetVnodeSummary(vnode):
1582 """ Get a summary of important information out of vnode
1583 """
1584 out_str = ''
1585 format_string = "{0: <#020x} {1: >8d} {2: >8d} {3: <#020x} {4: <6s} {5: <#020x} {6: <6s} {7: <35s}"
1586 usecount = int(vnode.v_usecount)
1587 iocount = int(vnode.v_iocount)
1588 v_data_ptr = int(hex(vnode.v_data), 16)
1589 vtype = int(vnode.v_type)
1590 vtype_str = "%d" % vtype
1591 vnode_types = ['VNON', 'VREG', 'VDIR', 'VBLK', 'VCHR', 'VLNK', 'VSOCK', 'VFIFO', 'VBAD', 'VSTR', 'VCPLX'] # see vnode.h for enum type definition
1592 if vtype >= 0 and vtype < len(vnode_types):
1593 vtype_str = vnode_types[vtype]
1594 parent_ptr = int(hex(vnode.v_parent), 16)
1595 name_ptr = int(hex(vnode.v_name), 16)
1596 name =""
1597 if name_ptr != 0:
1598 name = str(vnode.v_name)
1599 elif int(vnode.v_tag) == 16 :
1600 cnode = Cast(vnode.v_data, 'cnode *')
1601 name = "hfs: %s" % str( Cast(cnode.c_desc.cd_nameptr, 'char *'))
1602 mapped = '-'
1603 if (vtype == 1) and (vnode.v_un.vu_ubcinfo != 0):
1604 # Check to see if vnode is mapped/unmapped
1605 if (vnode.v_un.vu_ubcinfo.ui_flags & 0x8) != 0:
1606 mapped = '1'
1607 else:
1608 mapped = '0'
1609 out_str += format_string.format(vnode, usecount, iocount, v_data_ptr, vtype_str, parent_ptr, mapped, name)
1610 return out_str
1611
1612@lldb_command('showallvnodes')
1613def ShowAllVnodes(cmd_args=None):
1614 """ Display info about all vnodes
1615 """
1616 mntlist = kern.globals.mountlist
1617 print GetVnodeSummary.header
1618 for mntval in IterateTAILQ_HEAD(mntlist, 'mnt_list'):
1619 for vnodeval in IterateTAILQ_HEAD(mntval.mnt_vnodelist, 'v_mntvnodes'):
1620 print GetVnodeSummary(vnodeval)
1621 return
1622
1623@lldb_command('showvnode')
1624def ShowVnode(cmd_args=None):
1625 """ Display info about one vnode
1626 usage: showvnode <vnode>
1627 """
1628 if cmd_args == None or len(cmd_args) < 1:
1629 print "Please provide valid vnode argument. Type help showvnode for help."
1630 return
1631 vnodeval = kern.GetValueFromAddress(cmd_args[0],'vnode *')
1632 print GetVnodeSummary.header
1633 print GetVnodeSummary(vnodeval)
1634
1635@lldb_command('showvolvnodes')
1636def ShowVolVnodes(cmd_args=None):
1637 """ Display info about all vnodes of a given mount_t
1638 """
1639 if cmd_args == None or len(cmd_args) < 1:
1640 print "Please provide a valide mount_t argument. Try 'help showvolvnodes' for help"
1641 return
1642 mntval = kern.GetValueFromAddress(cmd_args[0], 'mount_t')
1643 print GetVnodeSummary.header
1644 for vnodeval in IterateTAILQ_HEAD(mntval.mnt_vnodelist, 'v_mntvnodes'):
1645 print GetVnodeSummary(vnodeval)
1646 return
1647
1648@lldb_command('showvolbusyvnodes')
1649def ShowVolBusyVnodes(cmd_args=None):
1650 """ Display info about busy (iocount!=0) vnodes of a given mount_t
1651 """
1652 if cmd_args == None or len(cmd_args) < 1:
1653 print "Please provide a valide mount_t argument. Try 'help showvolbusyvnodes' for help"
1654 return
1655 mntval = kern.GetValueFromAddress(cmd_args[0], 'mount_t')
1656 print GetVnodeSummary.header
1657 for vnodeval in IterateTAILQ_HEAD(mntval.mnt_vnodelist, 'v_mntvnodes'):
1658 if int(vnodeval.v_iocount) != 0:
1659 print GetVnodeSummary(vnodeval)
1660
1661@lldb_command('showallbusyvnodes')
1662def ShowAllBusyVnodes(cmd_args=None):
1663 """ Display info about all busy (iocount!=0) vnodes
1664 """
1665 mntlistval = kern.globals.mountlist
1666 for mntval in IterateTAILQ_HEAD(mntlistval, 'mnt_list'):
1667 ShowVolBusyVnodes([hex(mntval)])
1668
1669@lldb_command('print_vnode')
1670def PrintVnode(cmd_args=None):
1671 """ Prints out the fields of a vnode struct
1672 Usage: print_vnode <vnode>
1673 """
1674 if not cmd_args:
1675 print "Please provide valid vnode argument. Type help print_vnode for help."
1676 return
1677 ShowVnode(cmd_args)
1678
1679@lldb_command('showworkqvnodes')
1680def ShowWorkqVnodes(cmd_args=None):
1681 """ Print the vnode worker list
1682 Usage: showworkqvnodes <struct mount *>
1683 """
1684 if not cmd_args:
1685 print "Please provide valid mount argument. Type help showworkqvnodes for help."
1686 return
1687
1688 mp = kern.GetValueFromAddress(cmd_args[0], 'mount *')
1689 vp = Cast(mp.mnt_workerqueue.tqh_first, 'vnode *')
1690 print GetVnodeSummary.header
1691 while int(vp) != 0:
1692 print GetVnodeSummary(vp)
1693 vp = vp.v_mntvnodes.tqe_next
1694
1695@lldb_command('shownewvnodes')
1696def ShowNewVnodes(cmd_args=None):
1697 """ Print the new vnode list
1698 Usage: shownewvnodes <struct mount *>
1699 """
1700 if not cmd_args:
1701 print "Please provide valid mount argument. Type help shownewvnodes for help."
1702 return
1703 mp = kern.GetValueFromAddress(cmd_args[0], 'mount *')
1704 vp = Cast(mp.mnt_newvnodes.tqh_first, 'vnode *')
1705 print GetVnodeSummary.header
1706 while int(vp) != 0:
1707 print GetVnodeSummary(vp)
1708 vp = vp.v_mntvnodes.tqe_next
1709
1710
1711@lldb_command('showprocvnodes')
1712def ShowProcVnodes(cmd_args=None):
1713 """ Routine to print out all the open fds which are vnodes in a process
1714 Usage: showprocvnodes <proc *>
1715 """
1716 if not cmd_args:
1717 print "Please provide valid proc argument. Type help showprocvnodes for help."
1718 return
1719 procptr = kern.GetValueFromAddress(cmd_args[0], 'proc *')
1720 fdptr = Cast(procptr.p_fd, 'filedesc *')
1721 if int(fdptr.fd_cdir) != 0:
1722 print '{0: <25s}\n{1: <s}\n{2: <s}'.format('Current Working Directory:', GetVnodeSummary.header, GetVnodeSummary(fdptr.fd_cdir))
1723 if int(fdptr.fd_rdir) != 0:
1724 print '{0: <25s}\n{1: <s}\n{2: <s}'.format('Current Root Directory:', GetVnodeSummary.header, GetVnodeSummary(fdptr.fd_rdir))
1725 count = 0
1726 print '\n' + '{0: <5s} {1: <7s}'.format('fd', 'flags') + GetVnodeSummary.header
1727 # Hack to get around <rdar://problem/12879494> llb fails to cast addresses to double pointers
1728 fpptr = Cast(fdptr.fd_ofiles, 'fileproc *')
1729 while count < fdptr.fd_nfiles:
1730 fpp = dereference(fpptr)
1731 fproc = Cast(fpp, 'fileproc *')
1732 if int(fproc) != 0:
1733 fglob = dereference(fproc).f_fglob
1734 flags = ""
1735 if (int(fglob) != 0) and (int(fglob.fg_ops.fo_type) == 1):
1736 if (fdptr.fd_ofileflags[count] & 1): flags += 'E'
1737 if (fdptr.fd_ofileflags[count] & 2): flags += 'F'
1738 if (fdptr.fd_ofileflags[count] & 4): flags += 'R'
1739 if (fdptr.fd_ofileflags[count] & 8): flags += 'C'
1740 print '{0: <5d} {1: <7s}'.format(count, flags) + GetVnodeSummary(Cast(fglob.fg_data, 'vnode *'))
1741 count += 1
1742 fpptr = kern.GetValueFromAddress(int(fpptr) + kern.ptrsize,'fileproc *')
1743
1744@lldb_command('showallprocvnodes')
1745def ShowAllProcVnodes(cmd_args=None):
1746 """ Routine to print out all the open fds which are vnodes
1747 """
1748
1749 procptr = Cast(kern.globals.allproc.lh_first, 'proc *')
1750 while procptr and int(procptr) != 0:
1751 print '{:<s}'.format("=" * 106)
1752 print GetProcInfo(procptr)
1753 ShowProcVnodes([int(procptr)])
1754 procptr = procptr.p_list.le_next
1755
1756@xnudebug_test('test_vnode')
1757def TestShowAllVnodes(kernel_target, config, lldb_obj, isConnected ):
1758 """ Test the functionality of vnode related commands
1759 returns
1760 - False on failure
1761 - True on success
1762 """
1763 if not isConnected:
1764 print "Target is not connected. Cannot test memstats"
1765 return False
1766 res = lldb.SBCommandReturnObject()
1767 lldb_obj.debugger.GetCommandInterpreter().HandleCommand("showallvnodes", res)
1768 result = res.GetOutput()
1769 if len(result.split("\n")) > 2 and result.find('VREG') != -1 and len(result.splitlines()[2].split()) > 5:
1770 return True
1771 else:
1772 return False
1773
1774# Macro: showallmtx
1775@lldb_type_summary(['_lck_grp_ *'])
1776def GetMutexEntry(mtxg):
1777 """ Summarize a mutex group entry with important information.
1778 params:
1779 mtxg: value - obj representing a mutex group in kernel
1780 returns:
1781 out_string - summary of the mutex group
1782 """
1783 out_string = ""
1784
1785 if kern.ptrsize == 8:
1786 format_string = '{0:#018x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1787 else:
1788 format_string = '{0:#010x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1789
1790 if mtxg.lck_grp_mtxcnt:
1791 out_string += format_string.format(mtxg, mtxg.lck_grp_mtxcnt,mtxg.lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_util_cnt,
1792 mtxg.lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_miss_cnt,
1793 mtxg.lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_wait_cnt, mtxg.lck_grp_name)
1794 return out_string
1795
1796@lldb_command('showallmtx')
1797def ShowAllMtx(cmd_args=None):
1798 """ Routine to print a summary listing of all mutexes
1799 """
1800
1801 if kern.ptrsize == 8:
1802 hdr_format = '{:<18s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
1803 else:
1804 hdr_format = '{:<10s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
1805
1806 print hdr_format.format('LCK GROUP', 'CNT', 'UTIL', 'MISS', 'WAIT', 'NAME')
1807
1808 mtxgrp_queue_head = kern.globals.lck_grp_queue
1809 mtxgrp_ptr_type = GetType('_lck_grp_ *')
1810
1811 for mtxgrp_ptr in IterateQueue(mtxgrp_queue_head, mtxgrp_ptr_type, "lck_grp_link"):
1812 print GetMutexEntry(mtxgrp_ptr)
1813 return
1814# EndMacro: showallmtx
1815
1816# Macro: showallrwlck
1817@lldb_type_summary(['_lck_grp_ *'])
1818def GetRWLEntry(rwlg):
1819 """ Summarize a reader writer lock group with important information.
1820 params:
1821 rwlg: value - obj representing a reader writer lock group in kernel
1822 returns:
1823 out_string - summary of the reader writer lock group
1824 """
1825 out_string = ""
1826
1827 if kern.ptrsize == 8:
1828 format_string = '{0:#018x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1829 else:
1830 format_string = '{0:#010x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
1831
1832 if rwlg.lck_grp_rwcnt:
1833 out_string += format_string.format(rwlg, rwlg.lck_grp_rwcnt,rwlg.lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_util_cnt,
1834 rwlg.lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_miss_cnt,
1835 rwlg.lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_wait_cnt, rwlg.lck_grp_name)
1836 return out_string
1837
1838@lldb_command('showallrwlck')
1839def ShowAllRWLck(cmd_args=None):
1840 """ Routine to print a summary listing of all read/writer locks
1841 """
1842 if kern.ptrsize == 8:
1843 hdr_format = '{:<18s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
1844 else:
1845 hdr_format = '{:<10s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
1846
1847 print hdr_format.format('LCK GROUP', 'CNT', 'UTIL', 'MISS', 'WAIT', 'NAME')
1848
1849 rwlgrp_queue_head = kern.globals.lck_grp_queue
1850 rwlgrp_ptr_type = GetType('_lck_grp_ *')
1851 for rwlgrp_ptr in IterateQueue(rwlgrp_queue_head, rwlgrp_ptr_type, "lck_grp_link"):
1852 print GetRWLEntry(rwlgrp_ptr)
1853 return
1854# EndMacro: showallrwlck
1855
1856#Macro: showbootermemorymap
1857@lldb_command('showbootermemorymap')
1858def ShowBooterMemoryMap(cmd_args=None):
1859 """ Prints out the phys memory map from kernelBootArgs
1860 Supported only on x86_64
1861 """
1862 if kern.arch == 'x86_64':
1863 voffset = unsigned(0xFFFFFF8000000000)
1864 else:
1865 print "showbootermemorymap not supported on this architecture"
1866 return
1867
1868 out_string = ""
1869
1870 # Memory type map
1871 memtype_dict = {
1872 0: 'Reserved',
1873 1: 'LoaderCode',
1874 2: 'LoaderData',
1875 3: 'BS_code',
1876 4: 'BS_data',
1877 5: 'RT_code',
1878 6: 'RT_data',
1879 7: 'Convention',
1880 8: 'Unusable',
1881 9: 'ACPI_recl',
1882 10: 'ACPI_NVS',
1883 11: 'MemMapIO',
1884 12: 'MemPortIO',
1885 13: 'PAL_code'
1886 }
1887
1888 boot_args = kern.globals.kernelBootArgs
1889 msize = boot_args.MemoryMapDescriptorSize
1890 mcount = (boot_args.MemoryMapSize) / unsigned(msize)
1891
1892 out_string += "{0: <12s} {1: <19s} {2: <19s} {3: <19s} {4: <10s}\n".format("Type", "Physical Start", "Number of Pages", "Virtual Start", "Attributes")
1893
1894 i = 0
1895 while i < mcount:
1896 mptr = kern.GetValueFromAddress(unsigned(boot_args.MemoryMap) + voffset + unsigned(i*msize), 'EfiMemoryRange *')
1897 mtype = unsigned(mptr.Type)
1898 if mtype in memtype_dict:
1899 out_string += "{0: <12s}".format(memtype_dict[mtype])
1900 else:
1901 out_string += "{0: <12s}".format("UNKNOWN")
1902
1903 if mptr.VirtualStart == 0:
1904 out_string += "{0: #019x} {1: #019x} {2: <19s} {3: #019x}\n".format(mptr.PhysicalStart, mptr.NumberOfPages, ' '*19, mptr.Attribute)
1905 else:
1906 out_string += "{0: #019x} {1: #019x} {2: #019x} {3: #019x}\n".format(mptr.PhysicalStart, mptr.NumberOfPages, mptr.VirtualStart, mptr.Attribute)
1907 i = i + 1
1908
1909 print out_string
1910#EndMacro: showbootermemorymap
1911