]> git.saurik.com Git - apple/xnu.git/blame - tools/lldbmacros/memory.py
xnu-7195.101.1.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.
fe8ab488 3 It is very critical that you read coding guidelines in Section E in README file.
39236c6e
A
4"""
5from xnu import *
fe8ab488
A
6import sys
7import shlex
39236c6e
A
8from utils import *
9import xnudefines
10from process import *
39037602 11import macho
f427ee49
A
12import json
13from ctypes import c_int64
14
15def vm_unpack_pointer(packed, params, type_str = 'void *'):
16 """ Unpack a pointer packed with VM_PACK_POINTER()
17 params:
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
21 returns:
22 The unpacked pointer
23 """
24 if params.vmpp_base_relative:
25 addr = unsigned(packed) << int(params.vmpp_shift)
26 if addr: addr += int(params.vmpp_base)
27 else:
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)
33
c3c9b80d 34def GetZPerCPU(root, cpu, element_type = None):
f427ee49
A
35 """ Iterates over a percpu variable
36 params:
37 root - value : Value object for per-cpu variable
c3c9b80d 38 cpu - int : the CPU number
f427ee49
A
39 element_type - str : Type of element
40 returns:
41 one slot
42 """
43 pagesize = kern.globals.page_size
44 mangle = 1 << (8 * kern.ptrsize - 1)
c3c9b80d
A
45 if element_type is None:
46 element_type = root.GetSBValue().GetType()
47 return kern.GetValueFromAddress((int(root) | mangle) + cpu * pagesize, element_type)
48
49def IterateZPerCPU(root, element_type = None):
50 """ Iterates over a percpu variable
51 params:
52 root - value : Value object for per-cpu variable
53 element_type - str : Type of element
54 returns:
55 one slot
56 """
f427ee49 57 for i in range(0, kern.globals.zpercpu_early_count):
c3c9b80d 58 yield GetZPerCPU(root, i, element_type)
f427ee49
A
59
60@lldb_command('showzpcpu', "S")
61def ShowZPerCPU(cmd_args=None, cmd_options={}):
62 """ Routine to show per-cpu zone allocated variables
63
64 Usage: showzpcpu [-S] expression [field]
65 -S : sum the values instead of printing them
66 """
67 if not cmd_args:
68 raise ArgumentError("No arguments passed")
69 pagesize = kern.globals.page_size
70 mangle = 1 << (8 * kern.ptrsize - 1)
71 sbv = pagesize.GetSBValue()
72 v = sbv.CreateValueFromExpression(None, cmd_args[0])
73 e = value(v)
74 acc = 0
75 for i in range(0, kern.globals.zpercpu_early_count):
76 if len(cmd_args) == 1:
77 t = sbv.CreateValueFromExpression(None, '(%s)%d' % (v.GetTypeName(), (int(e) | mangle) + i * pagesize)).Dereference()
78 else:
79 t = sbv.CreateValueFromExpression(None, '((%s)%d)->%s' % (v.GetTypeName(), (int(e) | mangle) + i * pagesize, cmd_args[1]))
80 if "-S" in cmd_options:
81 acc += value(t)
82 else:
83 print value(t)
84
85 if "-S" in cmd_options:
86 print acc
87
88def ZoneName(zone):
89 """ Formats the name for a given zone
90 params:
91 zone - value : A pointer to a zone
92 returns:
93 the formated name for the zone
94 """
95 names = [ "", "default.", "data.", "kext."]
96 return "{:s}{:s}".format(names[int(zone.kalloc_heap)], zone.z_name)
97
98def PrettyPrintDictionary(d):
99 """ Internal function to pretty print a dictionary with string or integer values
100 params: The dictionary to print
101 """
102 for key, value in d.items():
103 key += ":"
104 if isinstance(value, int):
105 print "{:<30s} {: >10d}".format(key, value)
106 else:
107 print "{:<30s} {: >10s}".format(key, value)
39236c6e
A
108
109# Macro: memstats
f427ee49
A
110@lldb_command('memstats', 'J')
111def Memstats(cmd_args=None, cmd_options={}):
39236c6e 112 """ 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.
f427ee49
A
113 usage: memstats -J
114 Output json
39236c6e 115 """
f427ee49
A
116 print_json = False
117 if "-J" in cmd_options:
118 print_json = True
119
120 memstats = {}
39236c6e 121 try:
f427ee49
A
122 memstats["memorystatus_level"] = int(kern.globals.memorystatus_level)
123 memstats["memorystatus_available_pages"] = int(kern.globals.memorystatus_available_pages)
124 memstats["inuse_ptepages_count"] = int(kern.globals.inuse_ptepages_count)
39236c6e
A
125 except ValueError:
126 pass
f427ee49
A
127 if hasattr(kern.globals, 'compressor_object'):
128 memstats["compressor_page_count"] = int(kern.globals.compressor_object.resident_page_count)
129 memstats["vm_page_throttled_count"] = int(kern.globals.vm_page_throttled_count)
130 memstats["vm_page_active_count"] = int(kern.globals.vm_page_active_count)
131 memstats["vm_page_inactive_count"] = int(kern.globals.vm_page_inactive_count)
132 memstats["vm_page_wire_count"] = int(kern.globals.vm_page_wire_count)
133 memstats["vm_page_free_count"] = int(kern.globals.vm_page_free_count)
134 memstats["vm_page_purgeable_count"] = int(kern.globals.vm_page_purgeable_count)
135 memstats["vm_page_inactive_target"] = int(kern.globals.vm_page_inactive_target)
136 memstats["vm_page_free_target"] = int(kern.globals.vm_page_free_target)
137 memstats["vm_page_free_reserved"] = int(kern.globals.vm_page_free_reserved)
138
139 if print_json:
140 print json.dumps(memstats)
141 else:
142 PrettyPrintDictionary(memstats)
39236c6e
A
143
144@xnudebug_test('test_memstats')
145def TestMemstats(kernel_target, config, lldb_obj, isConnected ):
146 """ Test the functionality of memstats command
5ba3f43e 147 returns
39236c6e 148 - False on failure
5ba3f43e 149 - True on success
39236c6e
A
150 """
151 if not isConnected:
152 print "Target is not connected. Cannot test memstats"
153 return False
154 res = lldb.SBCommandReturnObject()
155 lldb_obj.debugger.GetCommandInterpreter().HandleCommand("memstats", res)
156 result = res.GetOutput()
5ba3f43e 157 if result.split(":")[1].strip().find('None') == -1 :
39236c6e 158 return True
5ba3f43e 159 else:
39236c6e
A
160 return False
161
162# EndMacro: memstats
163
164# Macro: showmemorystatus
165def CalculateLedgerPeak(phys_footprint_entry):
166 """ Internal function to calculate ledger peak value for the given phys footprint entry
5ba3f43e 167 params: phys_footprint_entry - value representing struct ledger_entry *
39236c6e
A
168 return: value - representing the ledger peak for the given phys footprint entry
169 """
170 now = kern.globals.sched_tick / 20
cb323159
A
171 ledger_peak = long(phys_footprint_entry.le_credit) - long(phys_footprint_entry.le_debit)
172 if hasattr(phys_footprint_entry._le._le_max, 'le_interval_max') and (long(phys_footprint_entry._le._le_max.le_interval_max) > ledger_peak):
173 ledger_peak = long(phys_footprint_entry._le._le_max.le_interval_max)
39236c6e
A
174 return ledger_peak
175
f427ee49 176@header("{: >8s} {: >12s} {: >12s} {: >10s} {: >10s} {: >12s} {: >14s} {: >10s} {: >12s} {: >10s} {: >10s} {: >10s} {: <32s}\n".format(
cb323159 177'pid', 'effective', 'requested', 'state', 'relaunch', 'user_data', 'physical', 'iokit', 'footprint',
d9a64523 178'recent peak', 'lifemax', 'limit', 'command'))
39236c6e
A
179def GetMemoryStatusNode(proc_val):
180 """ Internal function to get memorystatus information from the given proc
181 params: proc - value representing struct proc *
182 return: str - formatted output information for proc object
183 """
184 out_str = ''
185 task_val = Cast(proc_val.task, 'task *')
186 task_ledgerp = task_val.ledger
187
188 task_physmem_footprint_ledger_entry = task_ledgerp.l_entries[kern.globals.task_ledgers.phys_mem]
fe8ab488 189 task_iokit_footprint_ledger_entry = task_ledgerp.l_entries[kern.globals.task_ledgers.iokit_mapped]
39236c6e
A
190 task_phys_footprint_ledger_entry = task_ledgerp.l_entries[kern.globals.task_ledgers.phys_footprint]
191 page_size = kern.globals.page_size
5ba3f43e 192
cb323159
A
193 phys_mem_footprint = (long(task_physmem_footprint_ledger_entry.le_credit) - long(task_physmem_footprint_ledger_entry.le_debit)) / page_size
194 iokit_footprint = (long(task_iokit_footprint_ledger_entry.le_credit) - long(task_iokit_footprint_ledger_entry.le_debit)) / page_size
195 phys_footprint = (long(task_phys_footprint_ledger_entry.le_credit) - long(task_phys_footprint_ledger_entry.le_debit)) / page_size
196 phys_footprint_limit = long(task_phys_footprint_ledger_entry.le_limit) / page_size
39236c6e
A
197 ledger_peak = CalculateLedgerPeak(task_phys_footprint_ledger_entry)
198 phys_footprint_spike = ledger_peak / page_size
cb323159 199 phys_footprint_lifetime_max = long(task_phys_footprint_ledger_entry._le._le_max.le_lifetime_max) / page_size
39236c6e 200
cb323159 201 format_string = '{0: >8d} {1: >12d} {2: >12d} {3: #011x} {4: >10d} {5: #011x} {6: >12d} {7: >10d} {8: >13d}'
39236c6e 202 out_str += format_string.format(proc_val.p_pid, proc_val.p_memstat_effectivepriority,
cb323159
A
203 proc_val.p_memstat_requestedpriority, proc_val.p_memstat_state, proc_val.p_memstat_relaunch_flags,
204 proc_val.p_memstat_userdata, phys_mem_footprint, iokit_footprint, phys_footprint)
39236c6e 205 if phys_footprint != phys_footprint_spike:
5ba3f43e 206 out_str += "{: >12d}".format(phys_footprint_spike)
39236c6e 207 else:
5ba3f43e
A
208 out_str += "{: >12s}".format('-')
209
210 out_str += "{: >10d} ".format(phys_footprint_lifetime_max)
f427ee49 211 out_str += "{: >10d} {: <32s}\n".format(phys_footprint_limit, GetProcName(proc_val))
5ba3f43e 212 return out_str
39236c6e
A
213
214@lldb_command('showmemorystatus')
215def ShowMemoryStatus(cmd_args=None):
216 """ Routine to display each entry in jetsam list with a summary of pressure statistics
217 Usage: showmemorystatus
218 """
219 bucket_index = 0
220 bucket_count = 20
221 print GetMemoryStatusNode.header
5ba3f43e
A
222 print "{: >21s} {: >12s} {: >38s} {: >10s} {: >12s} {: >10s} {: >10s}\n".format("priority", "priority", "(pages)", "(pages)", "(pages)",
223 "(pages)", "(pages)", "(pages)")
39236c6e
A
224 while bucket_index < bucket_count:
225 current_bucket = kern.globals.memstat_bucket[bucket_index]
226 current_list = current_bucket.list
227 current_proc = Cast(current_list.tqh_first, 'proc *')
228 while unsigned(current_proc) != 0:
229 print GetMemoryStatusNode(current_proc)
230 current_proc = current_proc.p_memstat_list.tqe_next
231 bucket_index += 1
232 print "\n\n"
233 Memstats()
5ba3f43e 234
39236c6e
A
235# EndMacro: showmemorystatus
236
f427ee49 237class ZoneMeta(object):
39037602 238 """
f427ee49 239 Helper class that helpers walking metadata
39037602 240 """
f427ee49 241
f427ee49
A
242 def __init__(self, addr, isPageIndex = False):
243 global kern
244 pagesize = kern.globals.page_size
245 zone_info = kern.GetGlobalVariable('zone_info')
246
c3c9b80d
A
247 def load_range(var):
248 return (unsigned(var.min_address), unsigned(var.max_address))
249
250 def in_range(x, r):
251 return x >= r[0] and x <= r[1]
252
253 FOREIGN = GetEnumValue('zone_addr_kind_t', 'ZONE_ADDR_FOREIGN')
254 NATIVE = GetEnumValue('zone_addr_kind_t', 'ZONE_ADDR_NATIVE')
255
256 self.meta_range = load_range(zone_info.zi_meta_range)
257 self.native_range = load_range(zone_info.zi_map_range[NATIVE])
258 self.foreign_range = load_range(zone_info.zi_map_range[FOREIGN])
259 self.addr_base = min(self.foreign_range[0], self.native_range[0])
f427ee49
A
260
261 addr = unsigned(addr)
262 if isPageIndex:
263 # sign extend
264 addr = value(pagesize.GetSBValue().CreateValueFromExpression(None,
265 '(long)(int)%d * %d' %(addr, pagesize)))
266 addr = unsigned(addr)
267
268 self.address = addr
269
c3c9b80d 270 if in_range(addr, self.meta_range):
f427ee49 271 self.kind = 'Metadata'
c3c9b80d 272 addr -= addr % sizeof('struct zone_page_metadata')
f427ee49
A
273 self.meta_addr = addr
274 self.meta = kern.GetValueFromAddress(addr, "struct zone_page_metadata *")
275
c3c9b80d
A
276 self.page_addr = self.addr_base + ((addr - self.meta_range[0]) / sizeof('struct zone_page_metadata') * pagesize)
277 elif in_range(addr, self.native_range) or in_range(addr, self.foreign_range):
f427ee49 278 addr &= ~(pagesize - 1)
c3c9b80d 279 page_idx = (addr - self.addr_base) / pagesize
f427ee49
A
280
281 self.kind = 'Element'
282 self.page_addr = addr
c3c9b80d 283 self.meta_addr = self.meta_range[0] + page_idx * sizeof('struct zone_page_metadata')
f427ee49 284 self.meta = kern.GetValueFromAddress(self.meta_addr, "struct zone_page_metadata *")
39037602 285 else:
f427ee49
A
286 self.kind = 'Unknown'
287 self.meta = None
288 self.page_addr = 0
289 self.meta_addr = 0
c3c9b80d
A
290
291 if self.meta:
292 self.zone = addressof(kern.globals.zone_array[self.meta.zm_index])
293 else:
294 self.zone = None
f427ee49
A
295
296 def isSecondaryPage(self):
c3c9b80d 297 return self.meta and self.meta.zm_chunk_len >= 0xe
f427ee49
A
298
299 def getPageCount(self):
c3c9b80d
A
300 n = self.meta and self.meta.zm_chunk_len or 0
301 if self.zone and self.zone.z_percpu:
302 n *= kern.globals.zpercpu_early_count
303 return n
304
305 def getAllocAvail(self):
306 if not self.meta: return 0
307 chunk_len = unsigned(self.meta.zm_chunk_len)
308 page_size = unsigned(kern.globals.page_size)
309 return chunk_len * page_size / self.zone.z_elem_size
f427ee49
A
310
311 def getAllocCount(self):
c3c9b80d
A
312 if not self.meta: return 0
313 return self.meta.zm_alloc_size / self.zone.z_elem_size
f427ee49
A
314
315 def getReal(self):
316 if self.isSecondaryPage():
c3c9b80d 317 return ZoneMeta(unsigned(self.meta) - sizeof('struct zone_page_metadata') * unsigned(self.meta.zm_page_index))
f427ee49
A
318
319 return self
320
c3c9b80d
A
321 def getElementAddress(self, addr):
322 meta = self.getReal()
323 esize = meta.zone.z_elem_size
324 start = meta.page_addr
39037602 325
c3c9b80d
A
326 if esize == 0:
327 return None
328
329 estart = addr - start
330 return unsigned(start + estart - (estart % esize))
331
332 def getInlineBitmapChunkLength(self):
333 if self.zone.z_percpu:
334 return unsigned(self.zone.z_chunk_pages)
335 return unsigned(self.meta.zm_chunk_len)
336
337 def getBitmapSize(self):
338 if not self.meta or self.zone.z_permanent or not self.meta.zm_chunk_len:
339 return 0
340 if self.meta.zm_inline_bitmap:
341 return -4 * self.getInlineBitmapChunkLength()
342 return 8 << (unsigned(self.meta.zm_bitmap) & 0x7);
343
344 def getBitmap(self):
345 if not self.meta or self.zone.z_permanent or not self.meta.zm_chunk_len:
346 return 0
347 if self.meta.zm_inline_bitmap:
348 return unsigned(addressof(self.meta.zm_bitmap))
349 bbase = unsigned(kern.globals.zone_info.zi_bits_range.min_address)
350 index = unsigned(self.meta.zm_bitmap) & ~0x7
351 return bbase + index;
352
353 def getFreeCountSlow(self):
354 if not self.meta or self.zone.z_permanent or not self.meta.zm_chunk_len:
355 return self.getAllocAvail() - self.getAllocCount()
356
357 n = 0
358 if self.meta.zm_inline_bitmap:
359 for i in xrange(0, self.getInlineBitmapChunkLength()):
360 m = kern.GetValueFromAddress(self.meta_addr + i * 16,
361 'struct zone_page_metadata *');
362 bits = unsigned(m.zm_bitmap)
363 while bits:
364 n += 1
365 bits &= bits - 1
366 else:
367 bitmap = kern.GetValueFromAddress(self.getBitmap(), 'uint64_t *')
368 for i in xrange(0, 1 << (unsigned(self.meta.zm_bitmap) & 0x7)):
369 bits = unsigned(bitmap[i])
370 while bits:
371 n += 1
372 bits &= bits - 1
373 return n
374
375 def isElementFree(self, addr):
376 meta = self.meta
377
378 if not meta or self.zone.z_permanent or not meta.zm_chunk_len:
379 return True
380
381 start = self.page_addr
382 esize = self.zone.z_elem_size
383 eidx = (addr - start) / esize
384
385 if meta.zm_inline_bitmap:
386 i = eidx / 32
387 m = unsigned(meta) + sizeof('struct zone_page_metadata') * i
388 bits = kern.GetValueFromAddress(m, meta).zm_bitmap
389 return (bits & (1 << (eidx % 32))) != 0
f427ee49 390
c3c9b80d
A
391 else:
392 bitmap = kern.GetValueFromAddress(self.getBitmap(), 'uint64_t *')
393 bits = unsigned(bitmap[eidx / 64])
394 return (bits & (1 << (eidx % 64))) != 0
f427ee49
A
395
396 def iterateElements(self):
397 if self.meta is None:
398 return
c3c9b80d
A
399 esize = self.zone.z_elem_size
400 start = 0
401 end = unsigned(kern.globals.page_size) * self.meta.zm_chunk_len
402 end -= end % esize
f427ee49 403
c3c9b80d
A
404 for offs in xrange(start, end, esize):
405 yield unsigned(self.page_addr + offs)
f427ee49 406
39037602 407@lldb_type_summary(['zone_page_metadata'])
c3c9b80d
A
408@header("{:<20s} {:<10s} {:<10s} {:<24s} {:<20s} {:<20s}".format(
409 'METADATA', 'PG_CNT', 'ALLOC_CNT', 'BITMAP', 'ZONE', 'NAME'))
39037602
A
410def GetZoneMetadataSummary(meta):
411 """ Summarize a zone metadata object
412 params: meta - obj representing zone metadata in the kernel
413 returns: str - summary of the zone metadata
414 """
39037602 415
f427ee49
A
416 if type(meta) != ZoneMeta:
417 meta = ZoneMeta(meta)
418
419 out_str = 'Metadata Description:\n' + GetZoneMetadataSummary.header + '\n'
420 if meta.isSecondaryPage():
c3c9b80d
A
421 out_str += "{:<#20x} {:<10d} {:<10d} {:<#18x} @{:<4d} {:<#20x} {:s}\n".format(
422 meta.meta_addr, 0, 0, 0, 0, 0, '(fake multipage meta)')
f427ee49 423 meta = meta.getReal()
c3c9b80d
A
424 out_str += "{:<#20x} {:<10d} {:<10d} {:<#18x} @{:<4d} {:<#20x} {:s}".format(
425 meta.meta_addr, meta.getPageCount(), meta.getAllocCount(),
426 meta.getBitmap(), meta.getBitmapSize(), meta.zone, ZoneName(meta.zone))
f427ee49
A
427 return out_str
428
c3c9b80d
A
429@header("{:<20s} {:<10s} {:<10s} {:<20s} {:<10s}".format(
430 'ADDRESS', 'TYPE', 'STATUS', 'PAGE_ADDR', 'OFFSET'))
39037602
A
431def WhatIs(addr):
432 """ Information about kernel pointer
433 """
39037602 434 global kern
f427ee49
A
435
436 meta = ZoneMeta(addr)
c3c9b80d 437 estart = None
f427ee49
A
438
439 if meta.meta is None:
440 out_str = "Address {:#018x} is outside of any zone map ({:#018x}-{:#018x})\n".format(
c3c9b80d 441 addr, meta.native_range[0], meta.native_range[-1] + 1)
39037602 442 else:
f427ee49
A
443 if meta.kind[0] == 'E': # element
444 page_offset_str = "{:d}/{:d}K".format(
445 addr - meta.page_addr, kern.globals.page_size / 1024)
c3c9b80d
A
446 estart = meta.getElementAddress(addr)
447 if estart is None:
448 status = "Unattributed"
449 elif meta.isElementFree(estart):
450 status = "Free"
451 else:
452 status = "Allocated"
f427ee49
A
453 else:
454 page_offset_str = "-"
c3c9b80d 455 status = "-"
f427ee49 456 out_str = WhatIs.header + '\n'
c3c9b80d
A
457 out_str += "{meta.address:<#20x} {meta.kind:<10s} {status:<10s} {meta.page_addr:<#20x} {:<10s}\n\n".format(
458 page_offset_str, meta=meta, status=status)
f427ee49
A
459 out_str += GetZoneMetadataSummary(meta) + '\n\n'
460
39037602 461 print out_str
f427ee49 462
c3c9b80d 463 if estart is not None:
f427ee49
A
464 print "Hexdump:\n"
465
c3c9b80d
A
466 meta = meta.getReal()
467 esize = meta.zone.z_elem_size
468 start = meta.page_addr
469 marks = {unsigned(addr): ">"}
f427ee49
A
470
471 try:
472 if estart > start:
473 data_array = kern.GetValueFromAddress(estart - 16, "uint8_t *")
474 print_hex_data(data_array[0:16], estart - 16, "")
f427ee49
A
475 except:
476 pass
477
c3c9b80d 478 print "------------------------------------------------------------------"
f427ee49
A
479 try:
480 data_array = kern.GetValueFromAddress(estart, "uint8_t *")
c3c9b80d 481 print_hex_data(data_array[0:esize], estart, "", marks)
f427ee49 482 except:
c3c9b80d 483 print "*** unable to read memory ***"
f427ee49 484 pass
c3c9b80d 485 print "------------------------------------------------------------------"
f427ee49
A
486
487 try:
f427ee49
A
488 data_array = kern.GetValueFromAddress(estart + esize, "uint8_t *")
489 print_hex_data(data_array[0:16], estart + esize, "")
490 except:
491 pass
39037602
A
492
493@lldb_command('whatis')
494def WhatIsHelper(cmd_args=None):
495 """ Routine to show information about a kernel pointer
496 Usage: whatis <address>
497 """
498 if not cmd_args:
499 raise ArgumentError("No arguments passed")
f427ee49 500 WhatIs(kern.GetValueFromAddress(cmd_args[0], 'void *'))
39037602 501
d9a64523
A
502# Macro: showzcache
503
504@lldb_type_summary(['zone','zone_t'])
c3c9b80d
A
505@header("{:18s} {:32s} {:>6s} {:>6s} {:>6s} {:>6s} {:>6s} {:>6s} {:<s}".format(
506 'ZONE', 'NAME', 'WSS', 'CONT', 'USED', 'FREE', 'CACHED', 'RECIRC', 'CPU_CACHES'))
507def GetZoneCacheCPUSummary(zone, verbose, O):
d9a64523
A
508 """ Summarize a zone's cache broken up per cpu
509 params:
510 zone: value - obj representing a zone in kernel
511 returns:
512 str - summary of the zone's per CPU cache contents
513 """
c3c9b80d
A
514 format_string = '{zone:#018x} {:32s} '
515 format_string += '{zone.z_elems_free_wss:6d} {cont:6.2f} '
516 format_string += '{used:6d} {zone.z_elems_free:6d} '
517 format_string += '{cached:6d} {recirc:6d} {cpuinfo:s}'
d9a64523
A
518 cache_elem_count = 0
519 cpu_info = ""
c3c9b80d 520 mag_capacity = unsigned(kern.GetGlobalVariable('zc_magazine_size'))
d9a64523
A
521 depot_capacity = kern.GetGlobalVariable('depot_element_count')
522
c3c9b80d
A
523 if zone.z_pcpu_cache:
524 if verbose:
525 cpu_info = None
526 for cache in IterateZPerCPU(zone.z_pcpu_cache):
527 if cpu_info is None:
528 cpu_info = "{ "
529 else:
530 cpu_info += ", "
531 per_cpu_count = unsigned(cache.zc_alloc_cur)
532 per_cpu_count += unsigned(cache.zc_free_cur)
533 per_cpu_count += unsigned(cache.zc_depot_cur) * mag_capacity
534 cache_elem_count += per_cpu_count
535 cpu_info += "{:3d} /{cache.zc_depot_max:3d}".format(per_cpu_count, cache=cache)
536 cpu_info += " }"
537 else:
538 depot_cur = 0
539 depot_max = 0
540 for cache in IterateZPerCPU(zone.z_pcpu_cache):
541 depot_cur += unsigned(cache.zc_alloc_cur)
542 depot_cur += unsigned(cache.zc_free_cur)
543 cache_elem_count += unsigned(cache.zc_depot_cur) * mag_capacity
544 depot_max += unsigned(cache.zc_depot_max)
545 cache_elem_count += depot_cur
546
547 cpus = unsigned(kern.globals.zpercpu_early_count)
548 cpu_info = "total: {:3d} / {:3d}, avg: {:5.1f} / {:5.1f}".format(
549 depot_cur, depot_max, float(depot_cur) / cpus, float(depot_max) / cpus)
550
551
552 print O.format(format_string, ZoneName(zone), cached=cache_elem_count,
553 used=zone.z_elems_avail - cache_elem_count - zone.z_elems_free,
554 cont=float(zone.z_contention_wma) / 256.,
555 recirc=zone.z_recirc_cur * mag_capacity,
556 zone=zone, cpuinfo = cpu_info)
d9a64523 557
c3c9b80d 558@lldb_command('showzcache', fancy=True)
f427ee49 559def ZcacheCPUPrint(cmd_args=None, cmd_options={}, O=None):
c3c9b80d
A
560 """
561 Routine to print a summary listing of all the kernel zones cache contents
562
563 Usage: showzcache [-V]
564
565 Use -V to see more detailed output
d9a64523
A
566 """
567 global kern
c3c9b80d 568 verbose = "-V" in cmd_options
f427ee49 569 with O.table(GetZoneCacheCPUSummary.header):
c3c9b80d
A
570 if len(cmd_args) == 1:
571 zone = kern.GetValueFromAddress(cmd_args[0], 'struct zone *')
572 GetZoneCacheCPUSummary(zone, verbose, O);
573 else:
574 for zval in kern.zones:
575 if zval.z_self:
576 GetZoneCacheCPUSummary(zval, verbose, O)
d9a64523 577
c3c9b80d 578# EndMacro: showzcache
d9a64523 579
39236c6e
A
580# Macro: zprint
581
f427ee49
A
582def GetZone(zone_val, marks):
583 """ Internal function which gets a phython dictionary containing important zone information.
584 params:
585 zone_val: value - obj representing a zone in kernel
586 returns:
587 zone - python dictionary with zone stats
588 """
c3c9b80d
A
589 pcpu_scale = 1
590 if zone_val.z_percpu:
591 pcpu_scale = unsigned(kern.globals.zpercpu_early_count)
f427ee49
A
592 pagesize = kern.globals.page_size
593 zone = {}
c3c9b80d
A
594 mag_capacity = unsigned(kern.GetGlobalVariable('zc_magazine_size'))
595 zone["page_count"] = unsigned(zone_val.z_wired_cur) * pcpu_scale
596 zone["allfree_page_count"] = unsigned(zone_val.z_wired_empty)
597
598 cache_elem_count = 0
599 if zone_val.z_pcpu_cache:
600 for cache in IterateZPerCPU(zone_val.z_pcpu_cache):
601 cache_elem_count += unsigned(cache.zc_alloc_cur)
602 cache_elem_count += unsigned(cache.zc_free_cur)
603 cache_elem_count += unsigned(cache.zc_depot_cur) * mag_capacity
604
605 zone["size"] = zone["page_count"] * pagesize
f427ee49 606
c3c9b80d
A
607 zone["free_size"] = zone_val.z_elems_free * zone_val.z_elem_size * pcpu_scale
608 zone["cached_size"] = cache_elem_count * zone_val.z_elem_size * pcpu_scale
609 zone["used_size"] = zone["size"] - zone["free_size"] - zone["cached_size"]
f427ee49 610
c3c9b80d
A
611 zone["element_count"] = zone_val.z_elems_avail - zone_val.z_elems_free - cache_elem_count
612 zone["cache_element_count"] = cache_elem_count
613 zone["free_element_count"] = zone_val.z_elems_free
614
615 if zone_val.z_percpu:
f427ee49 616 zone["allocation_size"] = unsigned(pagesize)
c3c9b80d 617 zone["allocation_ncpu"] = unsigned(zone_val.z_chunk_pages)
f427ee49 618 else:
c3c9b80d 619 zone["allocation_size"] = unsigned(zone_val.z_chunk_pages * pagesize)
f427ee49
A
620 zone["allocation_ncpu"] = 1
621 zone["allocation_count"] = zone["allocation_size"] / zone_val.z_elem_size
622 zone["allocation_waste"] = (zone["allocation_size"] % zone_val.z_elem_size) * zone["allocation_ncpu"]
c3c9b80d 623
f427ee49
A
624 if not zone_val.__getattr__("z_self") :
625 zone["destroyed"] = True
626 else:
627 zone["destroyed"] = False
628
629 for mark in marks:
630 if zone_val.__getattr__(mark[0]):
631 zone[mark[0]] = True
632 else:
633 zone[mark[0]] = False
634
f427ee49
A
635 zone["name"] = ZoneName(zone_val)
636 if zone_val.exhaustible:
637 zone["exhaustible"] = True
638 else:
639 zone["exhaustible"] = False
640
c3c9b80d
A
641 zone["sequester_page_count"] = (unsigned(zone_val.z_va_cur) -
642 unsigned(zone_val.z_wired_cur)) * pcpu_scale
643 zone["page_count_max"] = unsigned(zone_val.z_wired_max) * pcpu_scale
f427ee49
A
644
645 return zone
646
647
39236c6e 648@lldb_type_summary(['zone','zone_t'])
c3c9b80d
A
649@header(("{:<18s} {:_^47s} {:_^24s} {:_^13s} {:_^28s}\n"+
650"{:<18s} {:>11s} {:>11s} {:>11s} {:>11s} {:>8s} {:>7s} {:>7s} {:>6s} {:>6s} {:>8s} {:>6s} {:>5s} {:>7s} {:<18s} {:<20s}").format(
cb323159 651'', 'SIZE (bytes)', 'ELEMENTS (#)', 'PAGES', 'ALLOC CHUNK CONFIG',
c3c9b80d 652'ZONE', 'TOTAL', 'ALLOC', 'CACHE', 'FREE', 'ALLOC', 'CACHE', 'FREE', 'COUNT', 'FREE', 'SIZE (P)', 'ELTS', 'WASTE', 'ELT_SZ', 'FLAGS', 'NAME'))
f427ee49 653def GetZoneSummary(zone_val, marks, stats):
39236c6e 654 """ Summarize a zone with important information. See help zprint for description of each field
5ba3f43e 655 params:
f427ee49 656 zone_val: value - obj representing a zone in kernel
5ba3f43e 657 returns:
39236c6e
A
658 str - summary of the zone
659 """
3e170ce0 660 pagesize = kern.globals.page_size
f427ee49
A
661 out_string = ""
662 zone = GetZone(zone_val, marks)
5ba3f43e 663
c3c9b80d
A
664 pcpu_scale = 1
665 if zone_val.z_percpu:
666 pcpu_scale = unsigned(kern.globals.zpercpu_early_count)
667
668 format_string = '{zone:#018x} {zd[size]:11,d} {zd[used_size]:11,d} {zd[cached_size]:11,d} {zd[free_size]:11,d} '
669 format_string += '{zd[element_count]:8,d} {zd[cache_element_count]:7,d} {zone.z_elems_free:7,d} '
670 format_string += '{z_wired_cur:6,d} {z_wired_empty:6,d} '
671 format_string += '{alloc_size_kb:3,d}K ({zone.z_chunk_pages:d}) '
672 format_string += '{zd[allocation_count]:6,d} {zd[allocation_waste]:5,d} {z_elem_size:7,d} '
f427ee49 673 format_string += '{markings:<18s} {zone_name:<20s}'
5ba3f43e 674
39236c6e 675 markings=""
f427ee49 676 if zone["destroyed"]:
5ba3f43e 677 markings+="I"
c3c9b80d 678
39236c6e 679 for mark in marks:
f427ee49
A
680 if zone[mark[0]]:
681 markings += mark[1]
39236c6e
A
682 else:
683 markings+=" "
d9a64523 684
f427ee49 685 alloc_size_kb = zone["allocation_size"] / 1024
c3c9b80d
A
686 out_string += format_string.format(zone=zone_val, zd=zone,
687 z_wired_cur=unsigned(zone_val.z_wired_cur) * pcpu_scale,
688 z_wired_empty=unsigned(zone_val.z_wired_empty) * pcpu_scale,
689 z_elem_size=unsigned(zone_val.z_elem_size) * pcpu_scale,
690 alloc_size_kb=alloc_size_kb, markings=markings, zone_name=zone["name"])
f427ee49
A
691
692 if zone["exhaustible"] :
693 out_string += " (max: {:d})".format(zone["page_count_max"] * pagesize)
5ba3f43e 694
f427ee49
A
695 if zone["sequester_page_count"] != 0 :
696 out_string += " (sequester: {:d})".format(zone["sequester_page_count"])
697
698 stats["cur_size"] += zone["size"]
699 stats["used_size"] += zone["used_size"]
c3c9b80d 700 stats["cached_size"] += zone["cached_size"]
f427ee49
A
701 stats["free_size"] += zone["free_size"]
702 stats["cur_pages"] += zone["page_count"]
703 stats["free_pages"] += zone["allfree_page_count"]
704 stats["seq_pages"] += zone["sequester_page_count"]
5ba3f43e 705
39236c6e
A
706 return out_string
707
f427ee49 708@lldb_command('zprint', "J", fancy=True)
cb323159 709def Zprint(cmd_args=None, cmd_options={}, O=None):
39236c6e 710 """ Routine to print a summary listing of all the kernel zones
f427ee49
A
711 usage: zprint -J
712 Output json
39236c6e
A
713 All columns are printed in decimal
714 Legend:
c3c9b80d
A
715 ! - zone uses VA sequestering
716 $ - not encrypted during hibernation
717 A - currently trying to allocate more backing memory from kernel_memory_allocate without VM priv
39236c6e 718 C - collectable
f427ee49 719 D - destructible
c3c9b80d 720 E - Per-cpu caching is enabled for this zone
f427ee49 721 F - allows foreign memory (memory not allocated from any zone map)
c3c9b80d
A
722 G - currently running GC
723 H - exhaustible
724 I - zone was destroyed and is no longer valid
725 L - zone is being monitored by zleaks
39236c6e 726 M - gzalloc will avoid monitoring this zone
39236c6e 727 N - zone requires alignment (avoids padding this zone for debugging)
c3c9b80d
A
728 O - does not allow refill callout to fill zone on noblock allocation
729 R - will be refilled when below low water mark
3e170ce0 730 S - currently trying to allocate more backing memory from kernel_memory_allocate with VM priv
39236c6e 731 W - another thread is waiting for more memory
c3c9b80d
A
732 X - expandable
733 Z - elements are zeroed on free
39236c6e
A
734 """
735 global kern
f427ee49
A
736
737 marks = [
738 ["collectable", "C"],
c3c9b80d 739 ["z_destructible", "D"],
f427ee49 740 ["expandable", "X"],
c3c9b80d 741 ["z_noencrypt", "$"],
f427ee49 742 ["exhaustible", "H"],
c3c9b80d
A
743 ["z_allows_foreign", "F"],
744 ["z_elems_rsv", "R"],
f427ee49
A
745 ["no_callout", "O"],
746 ["zleak_on", "L"],
c3c9b80d
A
747 ["z_expander", "A"],
748 ["z_expander_vm_priv", "S"],
749 ["z_replenish_wait", "W"],
750 ["z_pcpu_cache", "E"],
f427ee49
A
751 ["gzalloc_exempt", "M"],
752 ["alignment_required", "N"],
c3c9b80d
A
753 ["z_va_sequester", "!"],
754 ["z_free_zeroes", "Z"]
f427ee49 755 ]
c3c9b80d 756
f427ee49 757 stats = {
c3c9b80d 758 "cur_size": 0, "used_size": 0, "cached_size": 0, "free_size": 0,
f427ee49
A
759 "cur_pages": 0, "free_pages": 0, "seq_pages": 0
760 }
761
762 print_json = False
763 if "-J" in cmd_options:
764 print_json = True
765
766 if print_json:
767 zones = []
cb323159 768 for zval in kern.zones:
f427ee49
A
769 if zval.z_self:
770 zones.append(GetZone(zval, marks))
771
772 print json.dumps(zones)
773 else:
774 with O.table(GetZoneSummary.header):
775 for zval in kern.zones:
776 if zval.z_self:
777 print GetZoneSummary(zval, marks, stats)
778
c3c9b80d 779 format_string = '{VT.Bold}{name:19s} {stats[cur_size]:11,d} {stats[used_size]:11,d} {stats[cached_size]:11,d} {stats[free_size]:11,d} '
f427ee49
A
780 format_string += ' '
781 format_string += '{stats[cur_pages]:6,d} {stats[free_pages]:6,d}{VT.EndBold} '
782 format_string += '(sequester: {VT.Bold}{stats[seq_pages]:,d}{VT.EndBold})'
783 print O.format(format_string, name="TOTALS", filler="", stats=stats)
784
39236c6e
A
785
786@xnudebug_test('test_zprint')
787def TestZprint(kernel_target, config, lldb_obj, isConnected ):
788 """ Test the functionality of zprint command
5ba3f43e 789 returns
39236c6e 790 - False on failure
5ba3f43e 791 - True on success
39236c6e
A
792 """
793 if not isConnected:
794 print "Target is not connected. Cannot test memstats"
795 return False
796 res = lldb.SBCommandReturnObject()
797 lldb_obj.debugger.GetCommandInterpreter().HandleCommand("zprint", res)
798 result = res.GetOutput()
799 if len(result.split("\n")) > 2:
800 return True
5ba3f43e 801 else:
39236c6e
A
802 return False
803
804
805# EndMacro: zprint
c3c9b80d 806# Macro: showzchunks
39236c6e 807
f427ee49
A
808def ZoneIteratePageQueue(page):
809 while page.packed_address:
810 meta = ZoneMeta(page.packed_address, isPageIndex=True)
811 yield meta
812 page = meta.meta.zm_page_next
813
c3c9b80d
A
814@header("{: <20s} {: <20s} {: <20s} {: <25s} {: <10s} {: <8s} {: <4s} {: >9s}".format(
815 "Zone", "Metadata", "Page", "Bitmap", "Kind", "Queue", "Pgs", "Allocs"))
816def GetZoneChunk(meta, queue, O=None):
817 format_string = "{meta.zone: <#20x} "
818 format_string += "{meta.meta_addr: <#20x} {meta.page_addr: <#20x} "
819 format_string += "{bitmap: <#18x} @{bitmap_size:<5d} "
820 format_string += "{kind:<10s} {queue:<8s} {pgs:<1d}/{chunk:<1d} "
821 format_string += "{alloc_count: >4d}/{avail_count: >4d}"
822
823 pgs = int(meta.zone.z_chunk_pages)
824 chunk = pgs
825 if meta.meta.zm_chunk_len >= 0xe:
826 kind = "secondary"
827 pgs -= int(meta.meta.zm_page_index)
828 else:
829 kind = "primary"
830
831 alloc_count=meta.getAllocCount()
832 avail_count=meta.getAllocAvail()
833 free_count=meta.getFreeCountSlow()
834
835 if alloc_count + free_count != avail_count:
836 format_string += " {VT.Red}bitmap mismatch{VT.Default}"
837
838 return O.format(format_string, meta=meta,
839 alloc_count=alloc_count,
840 avail_count=avail_count,
841 bitmap=meta.getBitmap(),
842 bitmap_size=meta.getBitmapSize(),
843 queue=queue, kind=kind, pgs=pgs, chunk=chunk)
844
845def ShowZChunksImpl(zone, extra_addr=None, cmd_options={}, O=None):
846 verbose = '-V' in cmd_options
847
848 def do_content(meta, O, indent=False):
849 with O.table("{:>5s} {:<20s} {:<10s}".format("#", "Element", "State"), indent=indent):
850 i = 0
851 for e in meta.iterateElements():
852 status = "Allocated"
853 if meta.isElementFree(e):
854 status = "Free"
855 print O.format("{:5d} {:<#20x} {:10s}", i, e, status)
856 i += 1
857
858 if extra_addr is None:
859 with O.table(GetZoneChunk.header):
860 for meta in ZoneIteratePageQueue(zone.z_pageq_full):
861 print GetZoneChunk(meta, "full", O)
862 if verbose: do_content(meta, O, indent=True);
863
864 for meta in ZoneIteratePageQueue(zone.z_pageq_partial):
865 print GetZoneChunk(meta, "partial", O)
866 if verbose: do_content(meta, O, indent=True);
867
868 for meta in ZoneIteratePageQueue(zone.z_pageq_empty):
869 print GetZoneChunk(meta, "empty", O)
870 if verbose: do_content(meta, O, indent=True);
871
872 for meta in ZoneIteratePageQueue(zone.z_pageq_va):
873 print GetZoneChunk(meta, "va", O)
874 else:
875 meta = ZoneMeta(extra_addr, isPageIndex="-I" in cmd_options).getReal()
876 with O.table(GetZoneChunk.header):
877 print GetZoneChunk(meta, "N/A", O)
878 do_content(meta, O)
879
880@lldb_command('showzchunks', "IV", fancy=True)
881def ShowZChunks(cmd_args=None, cmd_options={}, O=None):
882 """
883 prints the list of zone chunks, or the content of a given chunk
884
885 Usage: showzchunks <zone> [-I] [-V] [address]
886
887 Use -I to interpret [address] as a page index
888 Use -V to show the contents of all the chunks
39236c6e 889
c3c9b80d 890 [address] can by any address belonging to the zone, or metadata
39236c6e 891 """
c3c9b80d 892
39236c6e 893 if not cmd_args:
c3c9b80d 894 return O.error('missing zone argument')
39236c6e
A
895
896 zone = kern.GetValueFromAddress(cmd_args[0], 'struct zone *')
39236c6e 897
c3c9b80d
A
898 if len(cmd_args) == 1:
899 ShowZChunksImpl(zone, cmd_options=cmd_options, O=O)
39236c6e 900 else:
c3c9b80d
A
901 addr = unsigned(kern.GetValueFromAddress(cmd_args[1]))
902 ShowZChunksImpl(zone, extra_addr=addr, cmd_options=cmd_options, O=O)
903
904@lldb_command('showallzchunks', fancy=True)
905def ShowAllZChunks(cmd_args=None, cmd_options={}, O=None):
906 """
907 prints the list of all zone chunks
908
909 Usage: showallzchunks
910 """
39236c6e 911
c3c9b80d
A
912 for z in kern.zones:
913 ShowZChunksImpl(z, O=O)
39236c6e 914
c3c9b80d 915# EndMacro: showzchunks
39037602
A
916# Macro: zstack_showzonesbeinglogged
917
918@lldb_command('zstack_showzonesbeinglogged')
919def ZstackShowZonesBeingLogged(cmd_args=None):
5ba3f43e 920 """ Show all zones which have BTLog enabled.
39037602 921 """
39037602
A
922 global kern
923 for zval in kern.zones:
924 if zval.zlog_btlog:
f427ee49 925 print "Zone: %s with its BTLog at: 0x%lx" % (ZoneName(zval), zval.zlog_btlog)
39037602
A
926
927# EndMacro: zstack_showzonesbeinglogged
928
39236c6e
A
929# Macro: zstack
930
931@lldb_command('zstack')
932def Zstack(cmd_args=None):
39037602
A
933 """ 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>.
934 Usage: zstack <btlog addr> <index> [<count>]
39236c6e 935
39037602
A
936 The suggested usage is to look at stacks with high percentage of refs (maybe > 25%).
937 The stack trace that occurs the most is probably the cause of the leak. Use zstack_findleak for that.
39236c6e
A
938 """
939 if not cmd_args:
940 print Zstack.__doc__
941 return
942 if int(kern.globals.log_records) == 0:
943 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
944 return
39236c6e 945
39037602
A
946 btlog_ptr = kern.GetValueFromAddress(cmd_args[0], 'btlog_t *')
947 btrecords_total_size = unsigned(btlog_ptr.btlog_buffersize)
948 btrecord_size = unsigned(btlog_ptr.btrecord_size)
949 btrecords = unsigned(btlog_ptr.btrecords)
950 btlog_size = unsigned(sizeof('struct btlog'))
951 depth = unsigned(btlog_ptr.btrecord_btdepth)
952 zstack_index = ArgumentStringToInt(cmd_args[1])
39236c6e 953 count = 1
39037602
A
954 if len(cmd_args) >= 3:
955 count = ArgumentStringToInt(cmd_args[2])
956
957 max_count = ((btrecords_total_size - btlog_size)/btrecord_size)
958
959 if (zstack_index + count) > max_count:
960 count = max_count - zstack_index
961
39236c6e 962 while count and (zstack_index != 0xffffff):
39037602
A
963 zstack_record_offset = zstack_index * btrecord_size
964 zstack_record = kern.GetValueFromAddress(btrecords + zstack_record_offset, 'btlog_record_t *')
965 if int(zstack_record.ref_count)!=0:
966 ShowZStackRecord(zstack_record, zstack_index, depth, unsigned(btlog_ptr.active_element_count))
967 zstack_index += 1
39236c6e
A
968 count -= 1
969
970# EndMacro : zstack
971
39037602 972# Macro: zstack_inorder
39236c6e 973
39037602
A
974@lldb_command('zstack_inorder')
975def ZstackInOrder(cmd_args=None):
976 """ Zone leak debugging: Print the stack traces starting from head to the tail.
977 Usage: zstack_inorder <btlog addr>
39236c6e 978 """
39037602
A
979 if not cmd_args:
980 print "Zone leak debugging: Print the stack traces starting from head to the tail. \nUsage: zstack_inorder <btlog addr>"
39236c6e 981 return
39037602
A
982 if int(kern.globals.log_records) == 0:
983 print "Zone logging not enabled. Add 'zlog=<zone name>' to boot-args."
39236c6e 984 return
39236c6e 985
39037602
A
986 btlog_ptr = kern.GetValueFromAddress(cmd_args[0], 'btlog_t *')
987 btrecords_total_size = unsigned(btlog_ptr.btlog_buffersize)
988 btrecord_size = unsigned(btlog_ptr.btrecord_size)
989 btrecords = unsigned(btlog_ptr.btrecords)
990 btlog_size = unsigned(sizeof('struct btlog'))
991 depth = unsigned(btlog_ptr.btrecord_btdepth)
992 zstack_head = unsigned(btlog_ptr.head)
993 zstack_index = zstack_head
994 zstack_tail = unsigned(btlog_ptr.tail)
995 count = ((btrecords_total_size - btlog_size)/btrecord_size)
996
997 while count and (zstack_index != 0xffffff):
998 zstack_record_offset = zstack_index * btrecord_size
999 zstack_record = kern.GetValueFromAddress(btrecords + zstack_record_offset, 'btlog_record_t *')
1000 ShowZStackRecord(zstack_record, zstack_index, depth, unsigned(btlog_ptr.active_element_count))
1001 zstack_index = zstack_record.next
1002 count -= 1
1003
1004# EndMacro : zstack_inorder
1005
1006# Macro: findoldest
1007
1008@lldb_command('findoldest')
1009def FindOldest(cmd_args=None):
1010 """
1011 """
1012 print "***** DEPRECATED ***** use 'zstack_findleak' macro instead."
1013 return
39236c6e
A
1014# EndMacro : findoldest
1015
39037602 1016# Macro : zstack_findleak
39236c6e 1017
39037602
A
1018@lldb_command('zstack_findleak')
1019def zstack_findleak(cmd_args=None):
1020 """ Zone leak debugging: search the log and print the stack with the most active references
39236c6e 1021 in the stack trace.
39037602 1022 Usage: zstack_findleak <btlog address>
39236c6e 1023
39037602
A
1024 This is useful for verifying a suspected stack as being the source of
1025 the leak.
39236c6e 1026 """
39037602
A
1027 btlog_ptr = kern.GetValueFromAddress(cmd_args[0], 'btlog_t *')
1028 btrecord_size = unsigned(btlog_ptr.btrecord_size)
1029 btrecords = unsigned(btlog_ptr.btrecords)
1030
1031 cpcs_index = unsigned(btlog_ptr.head)
1032 depth = unsigned(btlog_ptr.btrecord_btdepth)
1033 highref = 0
1034 highref_index = 0
1035 highref_record = 0
39236c6e
A
1036
1037 while cpcs_index != 0xffffff:
39037602
A
1038 cpcs_record_offset = cpcs_index * btrecord_size
1039 cpcs_record = kern.GetValueFromAddress(btrecords + cpcs_record_offset, 'btlog_record_t *')
1040 if cpcs_record.ref_count > highref:
1041 highref_record = cpcs_record
1042 highref = cpcs_record.ref_count
1043 highref_index = cpcs_index
39236c6e 1044 cpcs_index = cpcs_record.next
39037602 1045 ShowZStackRecord(highref_record, highref_index, depth, unsigned(btlog_ptr.active_element_count))
39236c6e 1046
39037602 1047# EndMacro: zstack_findleak
39236c6e
A
1048
1049# Macro: findelem
1050
1051@lldb_command('findelem')
1052def FindElem(cmd_args=None):
39037602
A
1053 """
1054 """
1055 print "***** DEPRECATED ***** use 'zstack_findelem' macro instead."
1056 return
1057# EndMacro: findelem
1058
1059@lldb_command('zstack_findelem')
1060def ZStackFindElem(cmd_args=None):
1061 """ Zone corruption debugging: search the zone log and print out the stack traces for all log entries that
5ba3f43e 1062 refer to the given zone element.
39037602 1063 Usage: zstack_findelem <btlog addr> <elem addr>
39236c6e
A
1064
1065 When the kernel panics due to a corrupted zone element, get the
1066 element address and use this command. This will show you the stack traces of all logged zalloc and
1067 zfree operations which tells you who touched the element in the recent past. This also makes
1068 double-frees readily apparent.
1069 """
1070 if not cmd_args:
39037602 1071 print ZStackFindElem.__doc__
39236c6e 1072 return
39037602
A
1073 if int(kern.globals.log_records) == 0 or unsigned(kern.globals.corruption_debug_flag) == 0:
1074 print "Zone logging with corruption detection not enabled. Add '-zc zlog=<zone name>' to boot-args."
39236c6e 1075 return
5ba3f43e 1076
39037602
A
1077 btlog_ptr = kern.GetValueFromAddress(cmd_args[0], 'btlog_t *')
1078 target_element = unsigned(kern.GetValueFromAddress(cmd_args[1], 'void *'))
1079
1080 btrecord_size = unsigned(btlog_ptr.btrecord_size)
1081 btrecords = unsigned(btlog_ptr.btrecords)
1082 depth = unsigned(btlog_ptr.btrecord_btdepth)
39236c6e 1083
39037602
A
1084 prev_op = -1
1085 scan_items = 0
1086 hashelem = cast(btlog_ptr.elem_linkage_un.element_hash_queue.tqh_first, 'btlog_element_t *')
1087 if (target_element >> 32) != 0:
1088 target_element = target_element ^ 0xFFFFFFFFFFFFFFFF
1089 else:
1090 target_element = target_element ^ 0xFFFFFFFF
1091 while hashelem != 0:
1092 if unsigned(hashelem.elem) == target_element:
1093 recindex = hashelem.recindex
1094 recoffset = recindex * btrecord_size
1095 record = kern.GetValueFromAddress(btrecords + recoffset, 'btlog_record_t *')
1096 out_str = ('-' * 8)
1097 if record.operation == 1:
1098 out_str += "OP: ALLOC. "
1099 else:
1100 out_str += "OP: FREE. "
1101 out_str += "Stack Index {0: <d} {1: <s}\n".format(recindex, ('-' * 8))
1102 print out_str
1103 print GetBtlogBacktrace(depth, record)
1104 print " \n"
1105 if int(record.operation) == prev_op:
39236c6e 1106 print "{0: <s} DOUBLE OP! {1: <s}".format(('*' * 8), ('*' * 8))
39037602
A
1107 return
1108 prev_op = int(record.operation)
1109 scan_items = 0
1110 hashelem = cast(hashelem.element_hash_link.tqe_next, 'btlog_element_t *')
1111 scan_items += 1
1112 if scan_items % 100 == 0:
1113 print "Scanning is ongoing. {0: <d} items scanned since last check." .format(scan_items)
39236c6e 1114
39037602 1115# EndMacro: zstack_findelem
39236c6e 1116
5ba3f43e
A
1117@lldb_command('zstack_findtop', 'N:')
1118def ShowZstackTop(cmd_args=None, cmd_options={}):
1119 """ Zone leak debugging: search the log and print the stacks with the most active references
1120 in the stack trace.
1121
1122 Usage: zstack_findtop [-N <n-stacks>] <btlog-addr>
1123 """
1124
1125 if not cmd_args:
1126 raise ArgumentError('Missing required btlog address argument')
1127
1128 n = 5
1129 if '-N' in cmd_options:
1130 n = int(cmd_options['-N'])
1131
1132 btlog_ptr = kern.GetValueFromAddress(cmd_args[0], 'btlog_t *')
1133 btrecord_size = unsigned(btlog_ptr.btrecord_size)
1134 btrecords = unsigned(btlog_ptr.btrecords)
1135
1136 cpcs_index = unsigned(btlog_ptr.head)
1137 depth = unsigned(btlog_ptr.btrecord_btdepth)
1138
1139 records = []
1140 while cpcs_index != 0xffffff:
1141 cpcs_record_offset = cpcs_index * btrecord_size
1142 cpcs_record = kern.GetValueFromAddress(btrecords + cpcs_record_offset, 'btlog_record_t *')
1143 cpcs_record.index = cpcs_index
1144 records.append(cpcs_record)
1145 cpcs_index = cpcs_record.next
1146
1147 recs = sorted(records, key=lambda x: x.ref_count, reverse=True)
1148
1149 for rec in recs[:n]:
1150 ShowZStackRecord(rec, rec.index, depth, unsigned(btlog_ptr.active_element_count))
1151
1152# EndMacro: zstack_findtop
1153
39236c6e
A
1154# Macro: btlog_find
1155
fe8ab488 1156@lldb_command('btlog_find', "AS")
39236c6e 1157def BtlogFind(cmd_args=None, cmd_options={}):
39236c6e 1158 """
39037602
A
1159 """
1160 print "***** DEPRECATED ***** use 'zstack_findelem' macro instead."
fe8ab488 1161 return
39236c6e
A
1162
1163#EndMacro: btlog_find
1164
1165#Macro: showzalloc
1166
1167@lldb_command('showzalloc')
1168def ShowZalloc(cmd_args=None):
1169 """ Prints a zallocation from the zallocations array based off its index and prints the associated symbolicated backtrace.
1170 Usage: showzalloc <index>
1171 """
1172 if not cmd_args:
1173 print ShowZalloc.__doc__
1174 return
1175 if unsigned(kern.globals.zallocations) == 0:
1176 print "zallocations array not initialized!"
1177 return
1178 zallocation = kern.globals.zallocations[ArgumentStringToInt(cmd_args[0])]
1179 print zallocation
1180 ShowZTrace([str(int(zallocation.za_trace_index))])
1181
1182#EndMacro: showzalloc
1183
1184#Macro: showztrace
1185
1186@lldb_command('showztrace')
1187def ShowZTrace(cmd_args=None):
1188 """ Prints the backtrace from the ztraces array at index
1189 Usage: showztrace <trace index>
1190 """
1191 if not cmd_args:
1192 print ShowZTrace.__doc__
1193 return
1194 if unsigned(kern.globals.ztraces) == 0:
1195 print "ztraces array not initialized!"
1196 return
1197 ztrace_addr = kern.globals.ztraces[ArgumentStringToInt(cmd_args[0])]
1198 print ztrace_addr
1199 ShowZstackTraceHelper(ztrace_addr.zt_stack, ztrace_addr.zt_depth)
1200
1201#EndMacro: showztrace
1202
1203#Macro: showztraceaddr
1204
1205@lldb_command('showztraceaddr')
1206def ShowZTraceAddr(cmd_args=None):
1207 """ Prints the struct ztrace passed in.
1208 Usage: showztraceaddr <trace address>
1209 """
1210 if not cmd_args:
1211 print ShowZTraceAddr.__doc__
1212 return
1213 ztrace_ptr = kern.GetValueFromAddress(cmd_args[0], 'struct ztrace *')
1214 print dereference(ztrace_ptr)
1215 ShowZstackTraceHelper(ztrace_ptr.zt_stack, ztrace_ptr.zt_depth)
1216
1217#EndMacro: showztraceaddr
1218
1219#Macro: showzstacktrace
1220
1221@lldb_command('showzstacktrace')
1222def ShowZstackTrace(cmd_args=None):
1223 """ Routine to print a stacktrace stored by OSBacktrace.
1224 Usage: showzstacktrace <saved stacktrace> [size]
1225
1226 size is optional, defaults to 15.
1227 """
1228 if not cmd_args:
1229 print ShowZstackTrace.__doc__
1230 return
1231 void_ptr_type = gettype('void *')
1232 void_double_ptr_type = void_ptr_type.GetPointerType()
1233 trace = kern.GetValueFromAddress(cmd_args[0], void_double_ptr_type)
1234 trace_size = 15
1235 if len(cmd_args) >= 2:
1236 trace_size = ArgumentStringToInt(cmd_args[1])
1237 ShowZstackTraceHelper(trace, trace_size)
5ba3f43e 1238
39236c6e
A
1239#EndMacro: showzstacktrace
1240
1241def ShowZstackTraceHelper(stack, depth):
1242 """ Helper routine for printing a zstack.
1243 params:
1244 stack: void *[] - An array of pointers representing the Zstack
5ba3f43e 1245 depth: int - The depth of the ztrace stack
39236c6e
A
1246 returns:
1247 None
1248 """
1249 trace_current = 0
1250 while trace_current < depth:
1251 trace_addr = stack[trace_current]
1252 symbol_arr = kern.SymbolicateFromAddress(unsigned(trace_addr))
1253 if symbol_arr:
1254 symbol_str = str(symbol_arr[0].addr)
1255 else:
1256 symbol_str = ''
1257 print '{0: <#x} {1: <s}'.format(trace_addr, symbol_str)
1258 trace_current += 1
1259
1260#Macro: showtopztrace
1261
1262@lldb_command('showtopztrace')
1263def ShowTopZtrace(cmd_args=None):
5ba3f43e 1264 """ Shows the ztrace with the biggest size.
39236c6e
A
1265 (According to top_ztrace, not by iterating through the hash table)
1266 """
1267 top_trace = kern.globals.top_ztrace
1268 print 'Index: {0: <d}'.format((unsigned(top_trace) - unsigned(kern.globals.ztraces)) / sizeof('struct ztrace'))
1269 print dereference(top_trace)
1270 ShowZstackTraceHelper(top_trace.zt_stack, top_trace.zt_depth)
1271
1272#EndMacro: showtopztrace
1273
1274#Macro: showzallocs
1275
1276@lldb_command('showzallocs')
1277def ShowZallocs(cmd_args=None):
1278 """ Prints all allocations in the zallocations table
1279 """
1280 if unsigned(kern.globals.zallocations) == 0:
1281 print "zallocations array not initialized!"
1282 return
5ba3f43e 1283 print '{0: <5s} {1: <18s} {2: <5s} {3: <15s}'.format('INDEX','ADDRESS','TRACE','SIZE')
39236c6e
A
1284 current_index = 0
1285 max_zallocation = unsigned(kern.globals.zleak_alloc_buckets)
1286 allocation_count = 0
1287 while current_index < max_zallocation:
1288 current_zalloc = kern.globals.zallocations[current_index]
1289 if int(current_zalloc.za_element) != 0:
1290 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))
1291 allocation_count += 1
1292 current_index += 1
1293 print 'Total Allocations: {0: <d}'.format(allocation_count)
1294
1295#EndMacro: showzallocs
1296
1297#Macro: showzallocsfortrace
1298
1299@lldb_command('showzallocsfortrace')
1300def ShowZallocsForTrace(cmd_args=None):
1301 """ Prints all allocations pointing to the passed in trace's index into ztraces by looking through zallocations table
1302 Usage: showzallocsfortrace <trace index>
1303 """
1304 if not cmd_args:
1305 print ShowZallocsForTrace.__doc__
1306 return
5ba3f43e 1307 print '{0: <5s} {1: <18s} {2: <15s}'.format('INDEX','ADDRESS','SIZE')
39236c6e
A
1308 target_index = ArgumentStringToInt(cmd_args[0])
1309 current_index = 0
1310 max_zallocation = unsigned(kern.globals.zleak_alloc_buckets)
1311 allocation_count = 0
1312 while current_index < max_zallocation:
1313 current_zalloc = kern.globals.zallocations[current_index]
1314 if unsigned(current_zalloc.za_element) != 0 and (unsigned(current_zalloc.za_trace_index) == unsigned(target_index)):
1315 print '{0: <5d} {1: <#018x} {2: <6d}'.format(current_index, current_zalloc.za_element, current_zalloc.za_size)
1316 allocation_count += 1
1317 current_index += 1
1318 print 'Total Allocations: {0: <d}'.format(allocation_count)
1319
1320#EndMacro: showzallocsfortrace
1321
1322#Macro: showztraces
1323
1324@lldb_command('showztraces')
1325def ShowZTraces(cmd_args=None):
1326 """ Prints all traces with size > 0
1327 """
1328 ShowZTracesAbove([0])
1329
1330#EndMacro: showztraces
1331
1332#Macro: showztracesabove
1333
1334@lldb_command('showztracesabove')
1335def ShowZTracesAbove(cmd_args=None):
1336 """ Prints all traces with size greater than X
1337 Usage: showztracesabove <size>
1338 """
1339 if not cmd_args:
1340 print ShowZTracesAbove.__doc__
1341 return
1342 print '{0: <5s} {1: <6s}'.format('INDEX','SIZE')
1343 current_index = 0
1344 ztrace_count = 0
1345 max_ztrace = unsigned(kern.globals.zleak_trace_buckets)
1346 while current_index < max_ztrace:
1347 ztrace_current = kern.globals.ztraces[current_index]
1348 if ztrace_current.zt_size > unsigned(cmd_args[0]):
1349 print '{0: <5d} {1: <6d}'.format(current_index, int(ztrace_current.zt_size))
1350 ztrace_count += 1
1351 current_index += 1
1352 print 'Total traces: {0: <d}'.format(ztrace_count)
1353
1354#EndMacro: showztracesabove
1355
1356#Macro: showztracehistogram
1357
1358@lldb_command('showztracehistogram')
1359def ShowZtraceHistogram(cmd_args=None):
1360 """ Prints the histogram of the ztrace table
1361 """
1362 print '{0: <5s} {1: <9s} {2: <10s}'.format('INDEX','HIT_COUNT','COLLISIONS')
1363 current_index = 0
1364 ztrace_count = 0
1365 max_ztrace = unsigned(kern.globals.zleak_trace_buckets)
1366 while current_index < max_ztrace:
1367 ztrace_current = kern.globals.ztraces[current_index]
1368 if ztrace_current.zt_hit_count != 0:
1369 print '{0: <5d} {1: <9d} {2: <10d}'.format(current_index, ztrace_current.zt_hit_count, ztrace_current.zt_collisions)
1370 ztrace_count += 1
1371 current_index += 1
1372 print 'Total traces: {0: <d}'.format(ztrace_count)
1373
1374#EndMacro: showztracehistogram
1375
1376#Macro: showzallochistogram
1377
1378@lldb_command('showzallochistogram')
1379def ShowZallocHistogram(cmd_args=None):
1380 """ Prints the histogram for the zalloc table
1381 """
1382 print '{0: <5s} {1: <9s}'.format('INDEX','HIT_COUNT')
1383 current_index = 0
1384 zallocation_count = 0
1385 max_ztrace = unsigned(kern.globals.zleak_alloc_buckets)
1386 while current_index < max_ztrace:
1387 zallocation_current = kern.globals.zallocations[current_index]
1388 if zallocation_current.za_hit_count != 0:
1389 print '{0: <5d} {1: <9d}'.format(current_index, zallocation_current.za_hit_count)
1390 zallocation_count += 1
1391 current_index += 1
1392 print 'Total Allocations: {0: <d}'.format(zallocation_count)
1393
1394#EndMacro: showzallochistogram
1395
1396#Macro: showzstats
1397
1398@lldb_command('showzstats')
1399def ShowZstats(cmd_args=None):
1400 """ Prints the zone leak detection stats
1401 """
1402 print 'z_alloc_collisions: {0: <d}, z_trace_collisions: {1: <d}'.format(unsigned(kern.globals.z_alloc_collisions), unsigned(kern.globals.z_trace_collisions))
1403 print 'z_alloc_overwrites: {0: <d}, z_trace_overwrites: {1: <d}'.format(unsigned(kern.globals.z_alloc_overwrites), unsigned(kern.globals.z_trace_overwrites))
1404 print 'z_alloc_recorded: {0: <d}, z_trace_recorded: {1: <d}'.format(unsigned(kern.globals.z_alloc_recorded), unsigned(kern.globals.z_trace_recorded))
1405
1406#EndMacro: showzstats
1407
f427ee49
A
1408#Macro: showpcpu
1409
1410@lldb_command('showpcpu', "N:V", fancy=True)
1411def ShowPCPU(cmd_args=None, cmd_options={}, O=None):
1412 """ Show per-cpu variables
1413 usage: showpcpu [-N <cpu>] [-V] <variable name>
1414
1415 Use -N <cpu> to only dump the value for a given CPU number
1416 Use -V to dump the values of the variables after their addresses
1417 """
1418
1419 if not cmd_args:
1420 raise ArgumentError("No arguments passed")
1421
1422 cpu = None
1423 ncpu = kern.globals.zpercpu_early_count
1424 pcpu_base = kern.globals.percpu_base
1425
1426 if "-N" in cmd_options:
1427 cpu = unsigned(int(cmd_options["-N"]))
1428 if cpu >= unsigned(ncpu):
1429 raise ArgumentError("Invalid cpu {d}".format(cpu))
1430
1431 var = addressof(kern.GetGlobalVariable('percpu_slot_' + cmd_args[0]))
1432 ty = var.GetSBValue().GetTypeName()
1433
1434 r = range(0, ncpu)
c3c9b80d 1435 if cpu is not None:
f427ee49
A
1436 r = range(cpu, cpu + 1)
1437
1438 def PCPUSlot(pcpu_var, i):
1439 if i == 0:
1440 return pcpu_var
1441 addr = unsigned(pcpu_var) + unsigned(pcpu_base.start) + (i - 1) * unsigned(pcpu_base.size)
1442 return kern.GetValueFromAddress(addr, pcpu_var)
1443
1444 with O.table("{:<4s} {:<20s}".format("CPU", "address")):
1445 for i in r:
1446 print O.format("{:<4d} ({:s}){:#x}", i, ty, PCPUSlot(var, i))
1447
1448 if not "-V" in cmd_options:
1449 return
1450
1451 for i in r:
1452 with O.table("CPU {:d}".format(i)):
1453 print dereference(PCPUSlot(var, i))
1454
1455#EndMacro: showpcpu
1456
fe8ab488
A
1457def GetBtlogBacktrace(depth, zstack_record):
1458 """ Helper routine for getting a BT Log record backtrace stack.
39236c6e
A
1459 params:
1460 depth:int - The depth of the zstack record
1461 zstack_record:btlog_record_t * - A BTLog record
1462 returns:
fe8ab488 1463 str - string with backtrace in it.
39236c6e
A
1464 """
1465 out_str = ''
1466 frame = 0
1467 if not zstack_record:
fe8ab488 1468 return "Zstack record none!"
5ba3f43e 1469
39236c6e
A
1470 depth_val = unsigned(depth)
1471 while frame < depth_val:
1472 frame_pc = zstack_record.bt[frame]
1473 if not frame_pc or int(frame_pc) == 0:
1474 break
1475 symbol_arr = kern.SymbolicateFromAddress(frame_pc)
1476 if symbol_arr:
1477 symbol_str = str(symbol_arr[0].addr)
1478 else:
1479 symbol_str = ''
1480 out_str += "{0: <#0x} <{1: <s}>\n".format(frame_pc, symbol_str)
1481 frame += 1
fe8ab488 1482 return out_str
39236c6e 1483
39037602 1484def ShowZStackRecord(zstack_record, zstack_index, btrecord_btdepth, elements_count):
39236c6e
A
1485 """ Helper routine for printing a single zstack record
1486 params:
1487 zstack_record:btlog_record_t * - A BTLog record
1488 zstack_index:int - Index for the record in the BTLog table
1489 returns:
1490 None
1491 """
1492 out_str = ('-' * 8)
1493 if zstack_record.operation == 1:
39037602 1494 out_str += "ALLOC. "
39236c6e 1495 else:
39037602
A
1496 out_str += "FREE. "
1497 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))
39236c6e 1498 print out_str
39037602
A
1499 print GetBtlogBacktrace(btrecord_btdepth, zstack_record)
1500 print " \n"
39236c6e
A
1501
1502# Macro: showioalloc
1503
1504@lldb_command('showioalloc')
1505def ShowIOAllocations(cmd_args=None):
1506 """ Show some accounting of memory allocated by IOKit allocators. See ioalloccount man page for details.
1507 Routine to display a summary of memory accounting allocated by IOKit allocators.
1508 """
1509 print "Instance allocation = {0: <#0x} = {1: d}K".format(kern.globals.debug_ivars_size, (kern.globals.debug_ivars_size / 1024))
1510 print "Container allocation = {0: <#0x} = {1: d}K".format(kern.globals.debug_container_malloc_size, (kern.globals.debug_container_malloc_size / 1024))
1511 print "IOMalloc allocation = {0: <#0x} = {1: d}K".format(kern.globals.debug_iomalloc_size, (kern.globals.debug_iomalloc_size / 1024))
1512 print "Container allocation = {0: <#0x} = {1: d}K".format(kern.globals.debug_iomallocpageable_size, (kern.globals.debug_iomallocpageable_size / 1024))
5ba3f43e
A
1513
1514
1515# EndMacro: showioalloc
39236c6e
A
1516
1517
3e170ce0
A
1518# Macro: showselectmem
1519@lldb_command('showselectmem', "S:")
1520def ShowSelectMem(cmd_args=None, cmd_options={}):
1521 """ Show memory cached by threads on calls to select.
1522
1523 usage: showselectmem [-v]
1524 -v : print each thread's memory
1525 (one line per thread with non-zero select memory)
1526 -S {addr} : Find the thread whose thread-local select set
1527 matches the given address
1528 """
1529 verbose = False
1530 opt_wqs = 0
1531 if config['verbosity'] > vHUMAN:
1532 verbose = True
1533 if "-S" in cmd_options:
1534 opt_wqs = unsigned(kern.GetValueFromAddress(cmd_options["-S"], 'uint64_t *'))
1535 if opt_wqs == 0:
1536 raise ArgumentError("Invalid waitq set address: {:s}".format(cmd_options["-S"]))
1537 selmem = 0
1538 if verbose:
1539 print "{:18s} {:10s} {:s}".format('Task', 'Thread ID', 'Select Mem (bytes)')
1540 for t in kern.tasks:
1541 for th in IterateQueue(t.threads, 'thread *', 'task_threads'):
1542 uth = Cast(th.uthread, 'uthread *');
1543 wqs = 0
1544 if hasattr(uth, 'uu_allocsize'): # old style
1545 thmem = uth.uu_allocsize
1546 wqs = uth.uu_wqset
1547 elif hasattr(uth, 'uu_wqstate_sz'): # new style
1548 thmem = uth.uu_wqstate_sz
1549 wqs = uth.uu_wqset
1550 else:
1551 print "What kind of uthread is this?!"
1552 return
1553 if opt_wqs and opt_wqs == unsigned(wqs):
1554 print "FOUND: {:#x} in thread: {:#x} ({:#x})".format(opt_wqs, unsigned(th), unsigned(th.thread_id))
1555 if verbose and thmem > 0:
1556 print "{:<#18x} {:<#10x} {:d}".format(unsigned(t), unsigned(th.thread_id), thmem)
1557 selmem += thmem
1558 print '-'*40
1559 print "Total: {:d} bytes ({:d} kbytes)".format(selmem, selmem/1024)
1560# Endmacro: showselectmem
5ba3f43e
A
1561
1562
39236c6e 1563# Macro: showtaskvme
fe8ab488
A
1564@lldb_command('showtaskvme', "PS")
1565def ShowTaskVmeHelper(cmd_args=None, cmd_options={}):
39236c6e
A
1566 """ Display a summary list of the specified vm_map's entries
1567 Usage: showtaskvme <task address> (ex. showtaskvme 0x00ataskptr00 )
3e170ce0
A
1568 Use -S flag to show VM object shadow chains
1569 Use -P flag to show pager info (mapped file, compressed pages, ...)
39236c6e 1570 """
fe8ab488
A
1571 show_pager_info = False
1572 show_all_shadows = False
1573 if "-P" in cmd_options:
1574 show_pager_info = True
1575 if "-S" in cmd_options:
1576 show_all_shadows = True
39236c6e 1577 task = kern.GetValueFromAddress(cmd_args[0], 'task *')
fe8ab488 1578 ShowTaskVMEntries(task, show_pager_info, show_all_shadows)
39236c6e 1579
fe8ab488
A
1580@lldb_command('showallvme', "PS")
1581def ShowAllVME(cmd_args=None, cmd_options={}):
39236c6e 1582 """ Routine to print a summary listing of all the vm map entries
fe8ab488
A
1583 Go Through each task in system and show the vm memory regions
1584 Use -S flag to show VM object shadow chains
1585 Use -P flag to show pager info (mapped file, compressed pages, ...)
1586 """
1587 show_pager_info = False
1588 show_all_shadows = False
1589 if "-P" in cmd_options:
1590 show_pager_info = True
1591 if "-S" in cmd_options:
1592 show_all_shadows = True
39236c6e 1593 for task in kern.tasks:
fe8ab488 1594 ShowTaskVMEntries(task, show_pager_info, show_all_shadows)
39236c6e
A
1595
1596@lldb_command('showallvm')
1597def ShowAllVM(cmd_args=None):
1598 """ Routine to print a summary listing of all the vm maps
1599 """
1600 for task in kern.tasks:
1601 print GetTaskSummary.header + ' ' + GetProcSummary.header
1602 print GetTaskSummary(task) + ' ' + GetProcSummary(Cast(task.bsd_info, 'proc *'))
1603 print GetVMMapSummary.header
1604 print GetVMMapSummary(task.map)
1605
1606@lldb_command("showtaskvm")
1607def ShowTaskVM(cmd_args=None):
1608 """ Display info about the specified task's vm_map
1609 syntax: (lldb) showtaskvm <task_ptr>
1610 """
1611 if not cmd_args:
1612 print ShowTaskVM.__doc__
1613 return False
1614 task = kern.GetValueFromAddress(cmd_args[0], 'task *')
1615 if not task:
1616 print "Unknown arguments."
1617 return False
1618 print GetTaskSummary.header + ' ' + GetProcSummary.header
1619 print GetTaskSummary(task) + ' ' + GetProcSummary(Cast(task.bsd_info, 'proc *'))
1620 print GetVMMapSummary.header
1621 print GetVMMapSummary(task.map)
1622 return True
1623
1624@lldb_command('showallvmstats')
1625def ShowAllVMStats(cmd_args=None):
1626 """ Print a summary of vm statistics in a table format
1627 """
3e170ce0 1628 page_size = kern.globals.page_size
39236c6e
A
1629 vmstats = lambda:None
1630 vmstats.wired_count = 0
1631 vmstats.resident_count = 0
1632 vmstats.resident_max = 0
1633 vmstats.internal = 0
1634 vmstats.external = 0
1635 vmstats.reusable = 0
1636 vmstats.compressed = 0
1637 vmstats.compressed_peak = 0
1638 vmstats.compressed_lifetime = 0
1639 vmstats.error = ''
1640
d9a64523
A
1641 hdr_format = "{:>6s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:>10s} {:<20s} {:1s}"
1642 print hdr_format.format('#ents', 'wired', 'vsize', 'rsize', 'NEW RSIZE', 'max rsize', 'internal', 'external', 'reusable', 'compressed', 'compressed', 'compressed', 'pid', 'command', '')
1643 print hdr_format.format('', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(current)', '(peak)', '(lifetime)', '', '', '')
f427ee49 1644 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}"
39236c6e
A
1645
1646 for task in kern.tasks:
1647 proc = Cast(task.bsd_info, 'proc *')
1648 vmmap = Cast(task.map, '_vm_map *')
1649 vmstats.error = ''
1650 vmstats.wired_count = vmmap.pmap.stats.wired_count;
1651 vmstats.resident_count = unsigned(vmmap.pmap.stats.resident_count);
1652 vmstats.resident_max = vmmap.pmap.stats.resident_max;
1653 vmstats.internal = unsigned(vmmap.pmap.stats.internal);
1654 vmstats.external = unsigned(vmmap.pmap.stats.external);
1655 vmstats.reusable = unsigned(vmmap.pmap.stats.reusable);
1656 vmstats.compressed = unsigned(vmmap.pmap.stats.compressed);
1657 vmstats.compressed_peak = unsigned(vmmap.pmap.stats.compressed_peak);
1658 vmstats.compressed_lifetime = unsigned(vmmap.pmap.stats.compressed_lifetime);
1659 vmstats.new_resident_count = vmstats.internal + vmstats.external
1660
1661 if vmstats.internal < 0:
1662 vmstats.error += '*'
1663 if vmstats.external < 0:
1664 vmstats.error += '*'
1665 if vmstats.reusable < 0:
1666 vmstats.error += '*'
1667 if vmstats.compressed < 0:
1668 vmstats.error += '*'
1669 if vmstats.compressed_peak < 0:
1670 vmstats.error += '*'
1671 if vmstats.compressed_lifetime < 0:
1672 vmstats.error += '*'
1673 if vmstats.new_resident_count +vmstats.reusable != vmstats.resident_count:
1674 vmstats.error += '*'
1675
f427ee49 1676 print entry_format.format(GetProcName(proc), p=proc, m=vmmap, vsize=(unsigned(vmmap.size) / page_size), t=task, s=vmstats)
5ba3f43e 1677
39236c6e 1678
fe8ab488 1679def ShowTaskVMEntries(task, show_pager_info, show_all_shadows):
39236c6e 1680 """ Routine to print out a summary listing of all the entries in a vm_map
5ba3f43e 1681 params:
39236c6e
A
1682 task - core.value : a object of type 'task *'
1683 returns:
1684 None
1685 """
1686 print "vm_map entries for task " + hex(task)
1687 print GetTaskSummary.header
1688 print GetTaskSummary(task)
1689 if not task.map:
1690 print "Task {0: <#020x} has map = 0x0"
1691 return None
1692 print GetVMMapSummary.header
1693 print GetVMMapSummary(task.map)
1694 vme_list_head = task.map.hdr.links
1695 vme_ptr_type = GetType('vm_map_entry *')
1696 print GetVMEntrySummary.header
1697 for vme in IterateQueue(vme_list_head, vme_ptr_type, "links"):
fe8ab488 1698 print GetVMEntrySummary(vme, show_pager_info, show_all_shadows)
39236c6e
A
1699 return None
1700
1701@lldb_command("showmap")
1702def ShowMap(cmd_args=None):
1703 """ Routine to print out info about the specified vm_map
1704 usage: showmap <vm_map>
1705 """
1706 if cmd_args == None or len(cmd_args) < 1:
1707 print "Invalid argument.", ShowMap.__doc__
1708 return
1709 map_val = kern.GetValueFromAddress(cmd_args[0], 'vm_map_t')
1710 print GetVMMapSummary.header
1711 print GetVMMapSummary(map_val)
1712
1713@lldb_command("showmapvme")
1714def ShowMapVME(cmd_args=None):
1715 """Routine to print out info about the specified vm_map and its vm entries
1716 usage: showmapvme <vm_map>
1717 """
1718 if cmd_args == None or len(cmd_args) < 1:
d9a64523 1719 print "Invalid argument.", ShowMapVME.__doc__
39236c6e
A
1720 return
1721 map_val = kern.GetValueFromAddress(cmd_args[0], 'vm_map_t')
1722 print GetVMMapSummary.header
1723 print GetVMMapSummary(map_val)
1724 vme_list_head = map_val.hdr.links
1725 vme_ptr_type = GetType('vm_map_entry *')
1726 print GetVMEntrySummary.header
1727 for vme in IterateQueue(vme_list_head, vme_ptr_type, "links"):
1728 print GetVMEntrySummary(vme)
1729 return None
1730
1731@lldb_type_summary(['_vm_map *', 'vm_map_t'])
f427ee49 1732@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"))
39236c6e
A
1733def GetVMMapSummary(vmmap):
1734 """ Display interesting bits from vm_map struct """
1735 out_string = ""
f427ee49 1736 format_string = "{0: <#020x} {1: <#020x} {2: <#020x} {3: >5d} {4: >5d} {5: <#020x} {6: <#020x} {7: >7d}"
39236c6e
A
1737 vm_size = uint64_t(vmmap.size).value
1738 resident_pages = 0
1739 if vmmap.pmap != 0: resident_pages = int(vmmap.pmap.stats.resident_count)
4bd07ac2 1740 first_free = 0
d9a64523 1741 if int(vmmap.holelistenabled) == 0: first_free = vmmap.f_s._first_free
f427ee49 1742 out_string += format_string.format(vmmap, vmmap.pmap, vm_size, vmmap.hdr.nentries, resident_pages, vmmap.hint, first_free, vmmap.hdr.page_shift)
39236c6e
A
1743 return out_string
1744
1745@lldb_type_summary(['vm_map_entry'])
1746@header("{0: <20s} {1: <20s} {2: <5s} {3: >7s} {4: <20s} {5: <20s}".format("entry", "start", "prot", "#page", "object", "offset"))
1747def GetVMEntrySummary(vme):
1748 """ Display vm entry specific information. """
3e170ce0 1749 page_size = kern.globals.page_size
39236c6e
A
1750 out_string = ""
1751 format_string = "{0: <#020x} {1: <#20x} {2: <1x}{3: <1x}{4: <3s} {5: >7d} {6: <#020x} {7: <#020x}"
1752 vme_protection = int(vme.protection)
1753 vme_max_protection = int(vme.max_protection)
1754 vme_extra_info_str ="SC-Ds"[int(vme.inheritance)]
5ba3f43e 1755 if int(vme.is_sub_map) != 0 :
39236c6e
A
1756 vme_extra_info_str +="s"
1757 elif int(vme.needs_copy) != 0 :
1758 vme_extra_info_str +="n"
3e170ce0
A
1759 num_pages = (unsigned(vme.links.end) - unsigned(vme.links.start)) / page_size
1760 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)
39236c6e
A
1761 return out_string
1762
1763# EndMacro: showtaskvme
1764@lldb_command('showmapwired')
1765def ShowMapWired(cmd_args=None):
1766 """ Routine to print out a summary listing of all the entries with wired pages in a vm_map
1767 """
1768 if cmd_args == None or len(cmd_args) < 1:
1769 print "Invalid argument", ShowMapWired.__doc__
1770 return
1771 map_val = kern.GetValueFromAddress(cmd_args[0], 'vm_map_t')
39037602 1772
39236c6e
A
1773
1774@lldb_type_summary(['kmod_info_t *'])
39037602 1775@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'))
39236c6e 1776def GetKextSummary(kmod):
5ba3f43e 1777 """ returns a string representation of kext information
39236c6e
A
1778 """
1779 out_string = ""
39037602
A
1780 format_string = "{0: <#020x} {1: <#020x} {2: <#020x} {3: >3d} {4: >5d} {5: <#020x} {6: <#020x} {7: >20s} {8: <30s}"
1781 segments, sections = GetAllSegmentsAndSectionsFromDataInMemory(unsigned(kmod.address), unsigned(kmod.size))
1782 text_segment = macho.get_text_segment(segments)
1783 if not text_segment:
1784 text_segment = segments[0]
1785 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)
39236c6e
A
1786 return out_string
1787
1788@lldb_type_summary(['uuid_t'])
5ba3f43e 1789@header("")
39236c6e
A
1790def GetUUIDSummary(uuid):
1791 """ returns a string representation like CA50DA4C-CA10-3246-B8DC-93542489AA26
1792 """
1793 arr = Cast(addressof(uuid), 'uint8_t *')
1794 data = []
1795 for i in range(16):
1796 data.append(int(arr[i]))
1797 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)
1798
1799@lldb_command('showallkmods')
1800def ShowAllKexts(cmd_args=None):
1801 """Display a summary listing of all loaded kexts (alias: showallkmods)
1802 """
1803 kmod_val = kern.globals.kmod
39037602 1804 kextuuidinfo = GetKextLoadInformation(show_progress=(config['verbosity'] > vHUMAN))
39236c6e 1805 print "{: <36s} ".format("UUID") + GetKextSummary.header
39236c6e
A
1806 for kval in IterateLinkedList(kmod_val, 'next'):
1807 uuid = "........-....-....-....-............"
1808 kaddr = unsigned(kval.address)
39037602 1809 found_kext_summary = None
39236c6e 1810 for l in kextuuidinfo :
39037602 1811 if kaddr == int(l[3],16):
39236c6e 1812 uuid = l[0]
39037602 1813 found_kext_summary = l
39236c6e 1814 break
39037602
A
1815 if found_kext_summary:
1816 _ksummary = GetKextSummary(found_kext_summary[7])
1817 else:
1818 _ksummary = GetKextSummary(kval)
1819 print uuid + " " + _ksummary
39236c6e 1820
39037602
A
1821def GetKmodWithAddr(addr):
1822 """ Go through kmod list and find one with begin_addr as addr
1823 returns: None if not found. else a cvalue of type kmod
1824 """
1825 kmod_val = kern.globals.kmod
1826 for kval in IterateLinkedList(kmod_val, 'next'):
1827 if addr == unsigned(kval.address):
1828 return kval
1829 return None
1830
1831def GetAllSegmentsAndSectionsFromDataInMemory(address, size):
1832 """ reads memory at address and parses mach_header to get segment and section information
1833 returns: Tuple of (segments_list, sections_list) like ([MachOSegment,...], [MachOSegment, ...])
1834 where MachOSegment has fields like 'name vmaddr vmsize fileoff filesize'
1835 if TEXT segment is not found a dummy segment & section with address, size is returned.
1836 """
1837 cache_hash = "kern.kexts.segments.{}.{}".format(address, size)
1838 cached_result = caching.GetDynamicCacheData(cache_hash,())
1839 if cached_result:
1840 return cached_result
1841
1842 defval = macho.MachOSegment('__TEXT', address, size, 0, size)
1843 if address == 0 or size == 0:
1844 return ([defval], [defval])
1845
5ba3f43e 1846 ## if int(kern.globals.gLoadedKextSummaries.version) <= 2:
39037602 1847 # until we have separate version. we will pay penalty only on arm64 devices
5ba3f43e 1848 if not kern.arch.startswith('arm64'):
39037602
A
1849 return ([defval], [defval])
1850
1851 restrict_size_to_read = 1536
1852 machoObject = None
1853 while machoObject is None:
1854 err = lldb.SBError()
1855 size_to_read = min(size, restrict_size_to_read)
1856 data = LazyTarget.GetProcess().ReadMemory(address, size_to_read, err)
1857 if not err.Success():
1858 print "Failed to read memory at {} and size {}".format(address, size_to_read)
1859 return ([defval], [defval])
1860 try:
1861 m = macho.MemMacho(data, len(data))
1862 machoObject = m
1863 except Exception as e:
1864 if str(e.message).find('unpack requires a string argument') >= 0:
1865 # this may be due to short read of memory. Lets do double read size.
1866 restrict_size_to_read *= 2
1867 debuglog("Bumping mach header read size to {}".format(restrict_size_to_read))
1868 continue
1869 else:
1870 print "Failed to read MachO for address {} errormessage: {}".format(address, e.message)
1871 return ([defval], [defval])
1872 # end of while loop. We have machoObject defined
1873 segments = machoObject.get_segments_with_name('')
1874 sections = machoObject.get_sections_with_name('')
1875 rval = (segments, sections)
1876 caching.SaveDynamicCacheData(cache_hash, rval)
1877 return rval
1878
1879def GetKextLoadInformation(addr=0, show_progress=False):
39236c6e
A
1880 """ Extract the kext uuid and load address information from the kernel data structure.
1881 params:
1882 addr - int - optional integer that is the address to search for.
39037602
A
1883 returns:
1884 [] - array with each entry of format
1885 ( 'UUID', 'Hex Load Address of __TEXT or __TEXT_EXEC section', 'name',
1886 'addr of macho header', [macho.MachOSegment,..], [MachoSection,...], kext, kmod_obj)
39236c6e 1887 """
39037602 1888 cached_result = caching.GetDynamicCacheData("kern.kexts.loadinformation", [])
5ba3f43e 1889 ## if specific addr is provided then ignore caching
39037602
A
1890 if cached_result and not addr:
1891 return cached_result
1892
1893 # because of <rdar://problem/12683084>, we can't find summaries directly
39236c6e
A
1894 #addr = hex(addressof(kern.globals.gLoadedKextSummaries.summaries))
1895 baseaddr = unsigned(kern.globals.gLoadedKextSummaries) + 0x10
1896 summaries_begin = kern.GetValueFromAddress(baseaddr, 'OSKextLoadedKextSummary *')
1897 total_summaries = int(kern.globals.gLoadedKextSummaries.numSummaries)
1898 kext_version = int(kern.globals.gLoadedKextSummaries.version)
1899 entry_size = 64 + 16 + 8 + 8 + 8 + 4 + 4
1900 if kext_version >= 2 :
1901 entry_size = int(kern.globals.gLoadedKextSummaries.entry_size)
1902 retval = []
1903 for i in range(total_summaries):
39037602
A
1904 if show_progress:
1905 print "progress: {}/{}".format(i, total_summaries)
39236c6e
A
1906 tmpaddress = unsigned(summaries_begin) + (i * entry_size)
1907 current_kext = kern.GetValueFromAddress(tmpaddress, 'OSKextLoadedKextSummary *')
39037602
A
1908 # code to extract macho information
1909 segments, sections = GetAllSegmentsAndSectionsFromDataInMemory(unsigned(current_kext.address), unsigned(current_kext.size))
1910 seginfo = macho.get_text_segment(segments)
1911 if not seginfo:
1912 seginfo = segments[0]
1913 kmod_obj = GetKmodWithAddr(unsigned(current_kext.address))
39236c6e 1914 if addr != 0 :
39037602
A
1915 if addr == unsigned(current_kext.address) or addr == seginfo.vmaddr:
1916 return [(GetUUIDSummary(current_kext.uuid) , hex(seginfo.vmaddr).rstrip('L'), str(current_kext.name), hex(current_kext.address), segments, seginfo, current_kext, kmod_obj)]
1917 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))
1918
1919 if not addr:
1920 caching.SaveDynamicCacheData("kern.kexts.loadinformation", retval)
39236c6e
A
1921 return retval
1922
1923lldb_alias('showallkexts', 'showallkmods')
1924
1925def GetOSKextVersion(version_num):
1926 """ returns a string of format 1.2.3x from the version_num
1927 params: version_num - int
39037602 1928 return: str
39236c6e
A
1929 """
1930 if version_num == -1 :
1931 return "invalid"
1932 (MAJ_MULT, MIN_MULT, REV_MULT,STAGE_MULT) = (100000000, 1000000, 10000, 1000)
1933 version = version_num
5ba3f43e 1934
39236c6e
A
1935 vers_major = version / MAJ_MULT
1936 version = version - (vers_major * MAJ_MULT)
5ba3f43e 1937
39236c6e
A
1938 vers_minor = version / MIN_MULT
1939 version = version - (vers_minor * MIN_MULT)
5ba3f43e 1940
39236c6e
A
1941 vers_revision = version / REV_MULT
1942 version = version - (vers_revision * REV_MULT)
5ba3f43e 1943
39236c6e
A
1944 vers_stage = version / STAGE_MULT
1945 version = version - (vers_stage * STAGE_MULT)
5ba3f43e
A
1946
1947 vers_stage_level = version
1948
39236c6e
A
1949 out_str = "%d.%d" % (vers_major, vers_minor)
1950 if vers_revision > 0: out_str += ".%d" % vers_revision
1951 if vers_stage == 1 : out_str += "d%d" % vers_stage_level
1952 if vers_stage == 3 : out_str += "a%d" % vers_stage_level
1953 if vers_stage == 5 : out_str += "b%d" % vers_stage_level
1954 if vers_stage == 6 : out_str += "fc%d" % vers_stage_level
5ba3f43e 1955
39236c6e
A
1956 return out_str
1957
1958@lldb_command('showallknownkmods')
1959def ShowAllKnownKexts(cmd_args=None):
1960 """ Display a summary listing of all kexts known in the system.
1961 This is particularly useful to find if some kext was unloaded before this crash'ed state.
1962 """
1963 kext_count = int(kern.globals.sKextsByID.count)
1964 index = 0
1965 kext_dictionary = kern.globals.sKextsByID.dictionary
1966 print "%d kexts in sKextsByID:" % kext_count
1967 print "{0: <20s} {1: <20s} {2: >5s} {3: >20s} {4: <30s}".format('OSKEXT *', 'load_addr', 'id', 'version', 'name')
1968 format_string = "{0: <#020x} {1: <20s} {2: >5s} {3: >20s} {4: <30s}"
39037602 1969
39236c6e
A
1970 while index < kext_count:
1971 kext_dict = GetObjectAtIndexFromArray(kext_dictionary, index)
1972 kext_name = str(kext_dict.key.string)
1973 osk = Cast(kext_dict.value, 'OSKext *')
1974 if int(osk.flags.loaded) :
1975 load_addr = "{0: <#020x}".format(osk.kmod_info)
1976 id = "{0: >5d}".format(osk.loadTag)
1977 else:
1978 load_addr = "------"
1979 id = "--"
1980 version_num = unsigned(osk.version)
1981 version = GetOSKextVersion(version_num)
1982 print format_string.format(osk, load_addr, id, version, kext_name)
1983 index += 1
39037602 1984
39236c6e
A
1985 return
1986
5ba3f43e
A
1987def FindKmodNameForAddr(addr):
1988 """ Given an address, return the name of the kext containing that address
1989 """
1990 addr = unsigned(addr)
1991 all_kexts_info = GetKextLoadInformation()
1992 for kinfo in all_kexts_info:
1993 segment = macho.get_segment_with_addr(kinfo[4], addr)
1994 if segment:
1995 return kinfo[7].name
1996 return None
1997
1998
1999@lldb_command('addkextaddr')
2000def AddKextAddr(cmd_args=[]):
2001 """ Given an address, load the kext which contains that address
2002 Syntax: (lldb) addkextaddr <addr>
2003 """
2004 if len(cmd_args) < 1:
2005 raise ArgumentError("Insufficient arguments")
2006
2007 addr = ArgumentStringToInt(cmd_args[0])
2008 all_kexts_info = GetKextLoadInformation()
d9a64523 2009 kernel_uuid = str(kern.globals.kernel_uuid_string).lower()
5ba3f43e
A
2010 found_kinfo = None
2011 found_segment = None
2012 for kinfo in all_kexts_info:
2013 segment = macho.get_segment_with_addr(kinfo[4], addr)
2014 if segment:
2015 print GetKextSummary.header
2016 print GetKextSummary(kinfo[7]) + " segment: {} offset = {:#0x}".format(segment.name, (addr - segment.vmaddr))
2017 cur_uuid = kinfo[0].lower()
d9a64523
A
2018 if (kernel_uuid == cur_uuid):
2019 print "(builtin)"
5ba3f43e 2020 else:
d9a64523
A
2021 print "Fetching dSYM for %s" % cur_uuid
2022 info = dsymForUUID(cur_uuid)
2023 if info and 'DBGSymbolRichExecutable' in info:
2024 print "Adding dSYM (%s) for %s" % (cur_uuid, info['DBGSymbolRichExecutable'])
2025 addDSYM(cur_uuid, info)
2026 loadDSYM(cur_uuid, int(kinfo[1],16), kinfo[4])
2027 else:
2028 print "Failed to get symbol info for %s" % cur_uuid
5ba3f43e
A
2029 return
2030
2031
39236c6e
A
2032@lldb_command('showkmodaddr')
2033def ShowKmodAddr(cmd_args=[]):
39037602 2034 """ Given an address, print the offset and name for the kmod containing it
39236c6e
A
2035 Syntax: (lldb) showkmodaddr <addr>
2036 """
2037 if len(cmd_args) < 1:
2038 raise ArgumentError("Insufficient arguments")
2039
2040 addr = ArgumentStringToInt(cmd_args[0])
39037602
A
2041 all_kexts_info = GetKextLoadInformation()
2042 found_kinfo = None
2043 found_segment = None
2044 for kinfo in all_kexts_info:
2045 s = macho.get_segment_with_addr(kinfo[4], addr)
2046 if s:
2047 found_segment = s
2048 found_kinfo = kinfo
2049 break
2050 if found_kinfo:
2051 print GetKextSummary.header
2052 print GetKextSummary(found_kinfo[7]) + " segment: {} offset = {:#0x}".format(found_segment.name, (addr - found_segment.vmaddr))
2053 return True
39236c6e
A
2054 return False
2055
39037602 2056
fe8ab488 2057@lldb_command('addkext','AF:N:')
39236c6e
A
2058def AddKextSyms(cmd_args=[], cmd_options={}):
2059 """ Add kext symbols into lldb.
2060 This command finds symbols for a uuid and load the required executable
39037602 2061 Usage:
39236c6e
A
2062 addkext <uuid> : Load one kext based on uuid. eg. (lldb)addkext 4DD2344C0-4A81-3EAB-BDCF-FEAFED9EB73E
2063 addkext -F <abs/path/to/executable> <load_address> : Load kext executable at specified load address
2064 addkext -N <name> : Load one kext that matches the name provided. eg. (lldb) addkext -N corecrypto
fe8ab488 2065 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
39037602 2066 addkext all : Will load all the kext symbols - SLOW
39236c6e 2067 """
39037602 2068
39236c6e
A
2069
2070 if "-F" in cmd_options:
2071 exec_path = cmd_options["-F"]
2072 exec_full_path = ResolveFSPath(exec_path)
2073 if not os.path.exists(exec_full_path):
2074 raise ArgumentError("Unable to resolve {:s}".format(exec_path))
2075
2076 if not os.path.isfile(exec_full_path):
2077 raise ArgumentError("Path is {:s} not a filepath. \nPlease check that path points to executable.\
2078\nFor ex. path/to/Symbols/IOUSBFamily.kext/Contents/PlugIns/AppleUSBHub.kext/Contents/MacOS/AppleUSBHub.\
2079\nNote: LLDB does not support adding kext based on directory paths like gdb used to.".format(exec_path))
39236c6e
A
2080
2081 slide_value = None
5ba3f43e 2082 sections = None
39236c6e
A
2083 if cmd_args:
2084 slide_value = cmd_args[0]
2085 debuglog("loading slide value from user input %s" % cmd_args[0])
2086
2087 filespec = lldb.SBFileSpec(exec_full_path, False)
2088 print "target modules add %s" % exec_full_path
2089 print lldb_run_command("target modules add %s" % exec_full_path)
2090 loaded_module = LazyTarget.GetTarget().FindModule(filespec)
2091 if loaded_module.IsValid():
2092 uuid_str = loaded_module.GetUUIDString()
2093 debuglog("added module %s with uuid %s" % (exec_full_path, uuid_str))
2094 if slide_value is None:
2095 all_kexts_info = GetKextLoadInformation()
2096 for k in all_kexts_info:
2097 debuglog(k[0])
2098 if k[0].lower() == uuid_str.lower():
2099 slide_value = k[1]
5ba3f43e 2100 sections = k[4]
39236c6e 2101 debuglog("found the slide %s for uuid %s" % (k[1], k[0]))
39236c6e
A
2102 if slide_value is None:
2103 raise ArgumentError("Unable to find load address for module described at %s " % exec_full_path)
5ba3f43e
A
2104
2105 if not sections:
2106 cmd_str = "target modules load --file %s --slide %s" % ( exec_full_path, str(slide_value))
2107 debuglog(cmd_str)
2108 else:
2109 cmd_str = "target modules load --file {} ".format(exec_full_path)
2110 sections_str = ""
2111 for s in sections:
2112 sections_str += " {} {:#0x} ".format(s.name, s.vmaddr)
2113 cmd_str += sections_str
2114 debuglog(cmd_str)
2115
2116 lldb.debugger.HandleCommand(cmd_str)
2117
39236c6e
A
2118 kern.symbolicator = None
2119 return True
2120
2121 all_kexts_info = GetKextLoadInformation()
d9a64523 2122 kernel_uuid = str(kern.globals.kernel_uuid_string).lower()
39037602 2123
39236c6e
A
2124 if "-N" in cmd_options:
2125 kext_name = cmd_options["-N"]
2126 kext_name_matches = GetLongestMatchOption(kext_name, [str(x[2]) for x in all_kexts_info], True)
fe8ab488 2127 if len(kext_name_matches) != 1 and "-A" not in cmd_options:
39236c6e
A
2128 print "Ambiguous match for name: {:s}".format(kext_name)
2129 if len(kext_name_matches) > 0:
2130 print "Options are:\n\t" + "\n\t".join(kext_name_matches)
2131 return
2132 debuglog("matched the kext to name %s and uuid %s" % (kext_name_matches[0], kext_name))
fe8ab488
A
2133 for cur_knm in kext_name_matches:
2134 for x in all_kexts_info:
2135 if cur_knm == x[2]:
2136 cur_uuid = x[0].lower()
d9a64523
A
2137 if (kernel_uuid == cur_uuid):
2138 print "(builtin)"
fe8ab488 2139 else:
d9a64523
A
2140 print "Fetching dSYM for {:s}".format(cur_uuid)
2141 info = dsymForUUID(cur_uuid)
2142 if info and 'DBGSymbolRichExecutable' in info:
2143 print "Adding dSYM ({0:s}) for {1:s}".format(cur_uuid, info['DBGSymbolRichExecutable'])
2144 addDSYM(cur_uuid, info)
2145 loadDSYM(cur_uuid, int(x[1],16), x[4])
2146 else:
2147 print "Failed to get symbol info for {:s}".format(cur_uuid)
fe8ab488 2148 break
39236c6e
A
2149 kern.symbolicator = None
2150 return
2151
2152 if len(cmd_args) < 1:
2153 raise ArgumentError("No arguments specified.")
2154
2155 uuid = cmd_args[0].lower()
2156
2157 load_all_kexts = False
2158 if uuid == "all":
2159 load_all_kexts = True
39037602 2160
39236c6e
A
2161 if not load_all_kexts and len(uuid_regex.findall(uuid)) == 0:
2162 raise ArgumentError("Unknown argument {:s}".format(uuid))
2163
2164 for k_info in all_kexts_info:
2165 cur_uuid = k_info[0].lower()
2166 if load_all_kexts or (uuid == cur_uuid):
d9a64523
A
2167 if (kernel_uuid != cur_uuid):
2168 print "Fetching dSYM for %s" % cur_uuid
2169 info = dsymForUUID(cur_uuid)
2170 if info and 'DBGSymbolRichExecutable' in info:
2171 print "Adding dSYM (%s) for %s" % (cur_uuid, info['DBGSymbolRichExecutable'])
2172 addDSYM(cur_uuid, info)
2173 loadDSYM(cur_uuid, int(k_info[1],16), k_info[4])
2174 else:
2175 print "Failed to get symbol info for %s" % cur_uuid
39236c6e
A
2176 #end of for loop
2177 kern.symbolicator = None
2178 return True
2179
39037602 2180
39236c6e
A
2181
2182lldb_alias('showkmod', 'showkmodaddr')
2183lldb_alias('showkext', 'showkmodaddr')
2184lldb_alias('showkextaddr', 'showkmodaddr')
2185
2186@lldb_type_summary(['mount *'])
fe8ab488 2187@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'))
39236c6e 2188def GetMountSummary(mount):
5ba3f43e 2189 """ Display a summary of mount on the system
39236c6e
A
2190 """
2191 out_string = ("{mnt: <#020x} {mnt.mnt_data: <#020x} {mnt.mnt_devvp: <#020x} {mnt.mnt_flag: <#012x} " +
2192 "{mnt.mnt_kern_flag: <#012x} {mnt.mnt_lflag: <#012x} {vfs.f_fstypename: >6s} " +
fe8ab488 2193 "{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'))
39236c6e
A
2194 return out_string
2195
2196@lldb_command('showallmounts')
2197def ShowAllMounts(cmd_args=None):
2198 """ Print all mount points
2199 """
2200 mntlist = kern.globals.mountlist
2201 print GetMountSummary.header
2202 for mnt in IterateTAILQ_HEAD(mntlist, 'mnt_list'):
2203 print GetMountSummary(mnt)
2204 return
2205
2206lldb_alias('ShowAllVols', 'showallmounts')
2207
2208@lldb_command('systemlog')
2209def ShowSystemLog(cmd_args=None):
2210 """ Display the kernel's printf ring buffer """
2211 msgbufp = kern.globals.msgbufp
2212 msg_size = int(msgbufp.msg_size)
2213 msg_bufx = int(msgbufp.msg_bufx)
2214 msg_bufr = int(msgbufp.msg_bufr)
2215 msg_bufc = msgbufp.msg_bufc
2216 msg_bufc_data = msg_bufc.GetSBValue().GetPointeeData(0, msg_size)
2217
2218 # the buffer is circular; start at the write pointer to end,
2219 # then from beginning to write pointer
2220 line = ''
2221 err = lldb.SBError()
2222 for i in range(msg_bufx, msg_size) + range(0, msg_bufx) :
2223 err.Clear()
2224 cbyte = msg_bufc_data.GetUnsignedInt8(err, i)
2225 if not err.Success() :
fe8ab488 2226 raise ValueError("Failed to read character at offset " + str(i) + ": " + err.GetCString())
39236c6e
A
2227 c = chr(cbyte)
2228 if c == '\0' :
2229 continue
2230 elif c == '\n' :
2231 print line
2232 line = ''
2233 else :
2234 line += c
2235
2236 if len(line) > 0 :
2237 print line
2238
2239 return
2240
2241@static_var('output','')
2242def _GetVnodePathName(vnode, vnodename):
2243 """ Internal function to get vnode path string from vnode structure.
2244 params:
2245 vnode - core.value
2246 vnodename - str
2247 returns Nothing. The output will be stored in the static variable.
2248 """
2249 if not vnode:
2250 return
2251 if int(vnode.v_flag) & 0x1 and int(hex(vnode.v_mount), 16) !=0:
2252 if int(vnode.v_mount.mnt_vnodecovered):
2253 _GetVnodePathName(vnode.v_mount.mnt_vnodecovered, str(vnode.v_mount.mnt_vnodecovered.v_name) )
2254 else:
2255 _GetVnodePathName(vnode.v_parent, str(vnode.v_parent.v_name))
5ba3f43e 2256 _GetVnodePathName.output += "/%s" % vnodename
39236c6e
A
2257
2258def GetVnodePath(vnode):
2259 """ Get string representation of the vnode
2260 params: vnodeval - value representing vnode * in the kernel
2261 return: str - of format /path/to/something
2262 """
2263 out_str = ''
2264 if vnode:
2265 if (int(vnode.v_flag) & 0x000001) and int(hex(vnode.v_mount), 16) != 0 and (int(vnode.v_mount.mnt_flag) & 0x00004000) :
2266 out_str += "/"
2267 else:
2268 _GetVnodePathName.output = ''
2269 if abs(vnode.v_name) != 0:
2270 _GetVnodePathName(vnode, str(vnode.v_name))
2271 out_str += _GetVnodePathName.output
2272 else:
2273 out_str += 'v_name = NULL'
2274 _GetVnodePathName.output = ''
2275 return out_str
2276
2277
2278@lldb_command('showvnodepath')
2279def ShowVnodePath(cmd_args=None):
2280 """ Prints the path for a vnode
2281 usage: showvnodepath <vnode>
2282 """
2283 if cmd_args != None and len(cmd_args) > 0 :
2284 vnode_val = kern.GetValueFromAddress(cmd_args[0], 'vnode *')
2285 if vnode_val:
2286 print GetVnodePath(vnode_val)
2287 return
2288
2289# Macro: showvnodedev
2290def GetVnodeDevInfo(vnode):
2291 """ Internal function to get information from the device type vnodes
2292 params: vnode - value representing struct vnode *
2293 return: str - formatted output information for block and char vnode types passed as param
2294 """
2295 vnodedev_output = ""
2296 vblk_type = GetEnumValue('vtype::VBLK')
2297 vchr_type = GetEnumValue('vtype::VCHR')
2298 if (vnode.v_type == vblk_type) or (vnode.v_type == vchr_type):
2299 devnode = Cast(vnode.v_data, 'devnode_t *')
2300 devnode_dev = devnode.dn_typeinfo.dev
2301 devnode_major = (devnode_dev >> 24) & 0xff
2302 devnode_minor = devnode_dev & 0x00ffffff
2303
5ba3f43e 2304 # boilerplate device information for a vnode
39236c6e
A
2305 vnodedev_output += "Device Info:\n\t vnode:\t\t{:#x}".format(vnode)
2306 vnodedev_output += "\n\t type:\t\t"
2307 if (vnode.v_type == vblk_type):
2308 vnodedev_output += "VBLK"
2309 if (vnode.v_type == vchr_type):
2310 vnodedev_output += "VCHR"
2311 vnodedev_output += "\n\t name:\t\t{:<s}".format(vnode.v_name)
2312 vnodedev_output += "\n\t major, minor:\t{:d},{:d}".format(devnode_major, devnode_minor)
2313 vnodedev_output += "\n\t mode\t\t0{:o}".format(unsigned(devnode.dn_mode))
2314 vnodedev_output += "\n\t owner (u,g):\t{:d} {:d}".format(devnode.dn_uid, devnode.dn_gid)
2315
2316 # decode device specific data
2317 vnodedev_output += "\nDevice Specific Information:\t"
2318 if (vnode.v_type == vblk_type):
2319 vnodedev_output += "Sorry, I do not know how to decode block devices yet!"
2320 vnodedev_output += "\nMaybe you can write me!"
2321
2322 if (vnode.v_type == vchr_type):
2323 # Device information; this is scanty
2324 # range check
2325 if (devnode_major > 42) or (devnode_major < 0):
2326 vnodedev_output += "Invalid major #\n"
2327 # static assignments in conf
2328 elif (devnode_major == 0):
2329 vnodedev_output += "Console mux device\n"
2330 elif (devnode_major == 2):
2331 vnodedev_output += "Current tty alias\n"
2332 elif (devnode_major == 3):
2333 vnodedev_output += "NULL device\n"
2334 elif (devnode_major == 4):
2335 vnodedev_output += "Old pty slave\n"
2336 elif (devnode_major == 5):
2337 vnodedev_output += "Old pty master\n"
2338 elif (devnode_major == 6):
2339 vnodedev_output += "Kernel log\n"
2340 elif (devnode_major == 12):
2341 vnodedev_output += "Memory devices\n"
2342 # Statically linked dynamic assignments
2343 elif unsigned(kern.globals.cdevsw[devnode_major].d_open) == unsigned(kern.GetLoadAddressForSymbol('ptmx_open')):
2344 vnodedev_output += "Cloning pty master not done\n"
2345 #GetVnodeDevCpty(devnode_major, devnode_minor)
2346 elif unsigned(kern.globals.cdevsw[devnode_major].d_open) == unsigned(kern.GetLoadAddressForSymbol('ptsd_open')):
2347 vnodedev_output += "Cloning pty slave not done\n"
2348 #GetVnodeDevCpty(devnode_major, devnode_minor)
2349 else:
2350 vnodedev_output += "RESERVED SLOT\n"
2351 else:
2352 vnodedev_output += "{:#x} is not a device".format(vnode)
2353 return vnodedev_output
2354
2355@lldb_command('showvnodedev')
2356def ShowVnodeDev(cmd_args=None):
2357 """ Routine to display details of all vnodes of block and character device types
2358 Usage: showvnodedev <address of vnode>
2359 """
2360 if not cmd_args:
2361 print "No arguments passed"
2362 print ShowVnodeDev.__doc__
2363 return False
2364 vnode_val = kern.GetValueFromAddress(cmd_args[0], 'vnode *')
2365 if not vnode_val:
2366 print "unknown arguments:", str(cmd_args)
2367 return False
2368 print GetVnodeDevInfo(vnode_val)
2369
2370# EndMacro: showvnodedev
2371
2372# Macro: showvnodelocks
2373def GetVnodeLock(lockf):
2374 """ Internal function to get information from the given advisory lock
2375 params: lockf - value representing v_lockf member in struct vnode *
2376 return: str - formatted output information for the advisory lock
2377 """
2378 vnode_lock_output = ''
2379 lockf_flags = lockf.lf_flags
2380 lockf_type = lockf.lf_type
2381 if lockf_flags & 0x20:
2382 vnode_lock_output += ("{: <8s}").format('flock')
2383 if lockf_flags & 0x40:
2384 vnode_lock_output += ("{: <8s}").format('posix')
2385 if lockf_flags & 0x80:
2386 vnode_lock_output += ("{: <8s}").format('prov')
2387 if lockf_flags & 0x10:
2388 vnode_lock_output += ("{: <4s}").format('W')
3e170ce0
A
2389 if lockf_flags & 0x400:
2390 vnode_lock_output += ("{: <8s}").format('ofd')
39236c6e
A
2391 else:
2392 vnode_lock_output += ("{: <4s}").format('.')
2393
2394 # POSIX file vs advisory range locks
2395 if lockf_flags & 0x40:
2396 lockf_proc = Cast(lockf.lf_id, 'proc *')
2397 vnode_lock_output += ("PID {: <18d}").format(lockf_proc.p_pid)
2398 else:
2399 vnode_lock_output += ("ID {: <#019x}").format(int(lockf.lf_id))
5ba3f43e 2400
39236c6e
A
2401 # lock type
2402 if lockf_type == 1:
2403 vnode_lock_output += ("{: <12s}").format('shared')
2404 else:
2405 if lockf_type == 3:
2406 vnode_lock_output += ("{: <12s}").format('exclusive')
2407 else:
2408 if lockf_type == 2:
2409 vnode_lock_output += ("{: <12s}").format('unlock')
2410 else:
2411 vnode_lock_output += ("{: <12s}").format('unknown')
5ba3f43e 2412
39236c6e
A
2413 # start and stop values
2414 vnode_lock_output += ("{: #018x} ..").format(lockf.lf_start)
2415 vnode_lock_output += ("{: #018x}\n").format(lockf.lf_end)
2416 return vnode_lock_output
2417
2418@header("{0: <3s} {1: <7s} {2: <3s} {3: <21s} {4: <11s} {5: ^19s} {6: ^17s}".format('*', 'type', 'W', 'held by', 'lock type', 'start', 'end'))
2419def GetVnodeLocksSummary(vnode):
2420 """ Internal function to get summary of advisory locks for the given vnode
2421 params: vnode - value representing the vnode object
2422 return: str - formatted output information for the summary of advisory locks
2423 """
2424 out_str = ''
2425 if vnode:
2426 lockf_list = vnode.v_lockf
2427 for lockf_itr in IterateLinkedList(lockf_list, 'lf_next'):
2428 out_str += ("{: <4s}").format('H')
2429 out_str += GetVnodeLock(lockf_itr)
2430 lockf_blocker = lockf_itr.lf_blkhd.tqh_first
2431 while lockf_blocker:
2432 out_str += ("{: <4s}").format('>')
2433 out_str += GetVnodeLock(lockf_blocker)
5ba3f43e 2434 lockf_blocker = lockf_blocker.lf_block.tqe_next
39236c6e
A
2435 return out_str
2436
2437@lldb_command('showvnodelocks')
2438def ShowVnodeLocks(cmd_args=None):
2439 """ Routine to display list of advisory record locks for the given vnode address
2440 Usage: showvnodelocks <address of vnode>
2441 """
2442 if not cmd_args:
2443 print "No arguments passed"
2444 print ShowVnodeLocks.__doc__
2445 return False
2446 vnode_val = kern.GetValueFromAddress(cmd_args[0], 'vnode *')
2447 if not vnode_val:
2448 print "unknown arguments:", str(cmd_args)
2449 return False
2450 print GetVnodeLocksSummary.header
2451 print GetVnodeLocksSummary(vnode_val)
2452
2453# EndMacro: showvnodelocks
2454
2455# Macro: showproclocks
5ba3f43e 2456
39236c6e
A
2457@lldb_command('showproclocks')
2458def ShowProcLocks(cmd_args=None):
2459 """ Routine to display list of advisory record locks for the given process
2460 Usage: showproclocks <address of proc>
2461 """
2462 if not cmd_args:
2463 print "No arguments passed"
2464 print ShowProcLocks.__doc__
2465 return False
2466 proc = kern.GetValueFromAddress(cmd_args[0], 'proc *')
2467 if not proc:
2468 print "unknown arguments:", str(cmd_args)
2469 return False
2470 out_str = ''
2471 proc_filedesc = proc.p_fd
2472 fd_lastfile = proc_filedesc.fd_lastfile
2473 fd_ofiles = proc_filedesc.fd_ofiles
2474 count = 0
2475 seen = 0
2476 while count <= fd_lastfile:
2477 if fd_ofiles[count]:
f427ee49 2478 fglob = fd_ofiles[count].fp_glob
39236c6e
A
2479 fo_type = fglob.fg_ops.fo_type
2480 if fo_type == 1:
2481 fg_data = fglob.fg_data
2482 fg_vnode = Cast(fg_data, 'vnode *')
2483 name = fg_vnode.v_name
2484 lockf_itr = fg_vnode.v_lockf
2485 if lockf_itr:
2486 if not seen:
2487 print GetVnodeLocksSummary.header
2488 seen = seen + 1
2489 out_str += ("\n( fd {:d}, name ").format(count)
2490 if not name:
2491 out_str += "(null) )\n"
2492 else:
2493 out_str += "{:s} )\n".format(name)
2494 print out_str
2495 print GetVnodeLocksSummary(fg_vnode)
2496 count = count + 1
2497 print "\n{0: d} total locks for {1: #018x}".format(seen, proc)
2498
2499# EndMacro: showproclocks
2500
2501@lldb_type_summary(['vnode_t', 'vnode *'])
f427ee49 2502@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'))
39236c6e
A
2503def GetVnodeSummary(vnode):
2504 """ Get a summary of important information out of vnode
2505 """
2506 out_str = ''
f427ee49 2507 format_string = "{0: <#020x} {1: >8d} {2: >8d} {3: >8d} {4: <#020x} {5: <6s} {6: <#020x} {7: <6s} {8: <6s} {9: <35s}"
39236c6e 2508 usecount = int(vnode.v_usecount)
f427ee49 2509 kusecount = int(vnode.v_kusecount)
39236c6e
A
2510 iocount = int(vnode.v_iocount)
2511 v_data_ptr = int(hex(vnode.v_data), 16)
2512 vtype = int(vnode.v_type)
2513 vtype_str = "%d" % vtype
2514 vnode_types = ['VNON', 'VREG', 'VDIR', 'VBLK', 'VCHR', 'VLNK', 'VSOCK', 'VFIFO', 'VBAD', 'VSTR', 'VCPLX'] # see vnode.h for enum type definition
2515 if vtype >= 0 and vtype < len(vnode_types):
2516 vtype_str = vnode_types[vtype]
2517 parent_ptr = int(hex(vnode.v_parent), 16)
2518 name_ptr = int(hex(vnode.v_name), 16)
2519 name =""
2520 if name_ptr != 0:
2521 name = str(vnode.v_name)
2522 elif int(vnode.v_tag) == 16 :
2523 cnode = Cast(vnode.v_data, 'cnode *')
2524 name = "hfs: %s" % str( Cast(cnode.c_desc.cd_nameptr, 'char *'))
2525 mapped = '-'
fe8ab488 2526 csblob_version = '-'
39236c6e 2527 if (vtype == 1) and (vnode.v_un.vu_ubcinfo != 0):
fe8ab488 2528 csblob_version = '{: <6d}'.format(vnode.v_un.vu_ubcinfo.cs_add_gen)
5ba3f43e 2529 # Check to see if vnode is mapped/unmapped
39236c6e
A
2530 if (vnode.v_un.vu_ubcinfo.ui_flags & 0x8) != 0:
2531 mapped = '1'
2532 else:
2533 mapped = '0'
f427ee49 2534 out_str += format_string.format(vnode, usecount, kusecount, iocount, v_data_ptr, vtype_str, parent_ptr, mapped, csblob_version, name)
39236c6e
A
2535 return out_str
2536
2537@lldb_command('showallvnodes')
2538def ShowAllVnodes(cmd_args=None):
2539 """ Display info about all vnodes
2540 """
2541 mntlist = kern.globals.mountlist
2542 print GetVnodeSummary.header
2543 for mntval in IterateTAILQ_HEAD(mntlist, 'mnt_list'):
2544 for vnodeval in IterateTAILQ_HEAD(mntval.mnt_vnodelist, 'v_mntvnodes'):
2545 print GetVnodeSummary(vnodeval)
2546 return
2547
2548@lldb_command('showvnode')
2549def ShowVnode(cmd_args=None):
2550 """ Display info about one vnode
2551 usage: showvnode <vnode>
2552 """
2553 if cmd_args == None or len(cmd_args) < 1:
2554 print "Please provide valid vnode argument. Type help showvnode for help."
2555 return
2556 vnodeval = kern.GetValueFromAddress(cmd_args[0],'vnode *')
2557 print GetVnodeSummary.header
2558 print GetVnodeSummary(vnodeval)
5ba3f43e 2559
39236c6e
A
2560@lldb_command('showvolvnodes')
2561def ShowVolVnodes(cmd_args=None):
2562 """ Display info about all vnodes of a given mount_t
2563 """
2564 if cmd_args == None or len(cmd_args) < 1:
2565 print "Please provide a valide mount_t argument. Try 'help showvolvnodes' for help"
2566 return
2567 mntval = kern.GetValueFromAddress(cmd_args[0], 'mount_t')
2568 print GetVnodeSummary.header
2569 for vnodeval in IterateTAILQ_HEAD(mntval.mnt_vnodelist, 'v_mntvnodes'):
2570 print GetVnodeSummary(vnodeval)
2571 return
2572
2573@lldb_command('showvolbusyvnodes')
2574def ShowVolBusyVnodes(cmd_args=None):
2575 """ Display info about busy (iocount!=0) vnodes of a given mount_t
2576 """
2577 if cmd_args == None or len(cmd_args) < 1:
2578 print "Please provide a valide mount_t argument. Try 'help showvolbusyvnodes' for help"
2579 return
2580 mntval = kern.GetValueFromAddress(cmd_args[0], 'mount_t')
2581 print GetVnodeSummary.header
2582 for vnodeval in IterateTAILQ_HEAD(mntval.mnt_vnodelist, 'v_mntvnodes'):
2583 if int(vnodeval.v_iocount) != 0:
2584 print GetVnodeSummary(vnodeval)
2585
2586@lldb_command('showallbusyvnodes')
2587def ShowAllBusyVnodes(cmd_args=None):
2588 """ Display info about all busy (iocount!=0) vnodes
2589 """
2590 mntlistval = kern.globals.mountlist
2591 for mntval in IterateTAILQ_HEAD(mntlistval, 'mnt_list'):
2592 ShowVolBusyVnodes([hex(mntval)])
2593
2594@lldb_command('print_vnode')
2595def PrintVnode(cmd_args=None):
2596 """ Prints out the fields of a vnode struct
2597 Usage: print_vnode <vnode>
2598 """
2599 if not cmd_args:
2600 print "Please provide valid vnode argument. Type help print_vnode for help."
2601 return
2602 ShowVnode(cmd_args)
2603
2604@lldb_command('showworkqvnodes')
2605def ShowWorkqVnodes(cmd_args=None):
2606 """ Print the vnode worker list
2607 Usage: showworkqvnodes <struct mount *>
2608 """
2609 if not cmd_args:
2610 print "Please provide valid mount argument. Type help showworkqvnodes for help."
2611 return
2612
2613 mp = kern.GetValueFromAddress(cmd_args[0], 'mount *')
2614 vp = Cast(mp.mnt_workerqueue.tqh_first, 'vnode *')
2615 print GetVnodeSummary.header
2616 while int(vp) != 0:
2617 print GetVnodeSummary(vp)
2618 vp = vp.v_mntvnodes.tqe_next
2619
2620@lldb_command('shownewvnodes')
2621def ShowNewVnodes(cmd_args=None):
2622 """ Print the new vnode list
2623 Usage: shownewvnodes <struct mount *>
2624 """
2625 if not cmd_args:
2626 print "Please provide valid mount argument. Type help shownewvnodes for help."
2627 return
2628 mp = kern.GetValueFromAddress(cmd_args[0], 'mount *')
2629 vp = Cast(mp.mnt_newvnodes.tqh_first, 'vnode *')
2630 print GetVnodeSummary.header
2631 while int(vp) != 0:
2632 print GetVnodeSummary(vp)
2633 vp = vp.v_mntvnodes.tqe_next
2634
2635
2636@lldb_command('showprocvnodes')
2637def ShowProcVnodes(cmd_args=None):
2638 """ Routine to print out all the open fds which are vnodes in a process
2639 Usage: showprocvnodes <proc *>
2640 """
2641 if not cmd_args:
2642 print "Please provide valid proc argument. Type help showprocvnodes for help."
2643 return
2644 procptr = kern.GetValueFromAddress(cmd_args[0], 'proc *')
2645 fdptr = Cast(procptr.p_fd, 'filedesc *')
2646 if int(fdptr.fd_cdir) != 0:
2647 print '{0: <25s}\n{1: <s}\n{2: <s}'.format('Current Working Directory:', GetVnodeSummary.header, GetVnodeSummary(fdptr.fd_cdir))
2648 if int(fdptr.fd_rdir) != 0:
2649 print '{0: <25s}\n{1: <s}\n{2: <s}'.format('Current Root Directory:', GetVnodeSummary.header, GetVnodeSummary(fdptr.fd_rdir))
2650 count = 0
cb323159 2651 print '\n' + '{0: <5s} {1: <7s} {2: <20s} '.format('fd', 'flags', 'fileglob') + GetVnodeSummary.header
39236c6e 2652 # Hack to get around <rdar://problem/12879494> llb fails to cast addresses to double pointers
cb323159 2653 fpptr = Cast(fdptr.fd_ofiles, 'uint64_t *')
39236c6e
A
2654 while count < fdptr.fd_nfiles:
2655 fpp = dereference(fpptr)
cb323159 2656 fproc = kern.GetValueFromAddress(int(fpp), 'fileproc *')
39236c6e 2657 if int(fproc) != 0:
f427ee49 2658 fglob = dereference(fproc).fp_glob
39236c6e
A
2659 flags = ""
2660 if (int(fglob) != 0) and (int(fglob.fg_ops.fo_type) == 1):
2661 if (fdptr.fd_ofileflags[count] & 1): flags += 'E'
2662 if (fdptr.fd_ofileflags[count] & 2): flags += 'F'
2663 if (fdptr.fd_ofileflags[count] & 4): flags += 'R'
2664 if (fdptr.fd_ofileflags[count] & 8): flags += 'C'
cb323159 2665 print '{0: <5d} {1: <7s} {2: <#020x} '.format(count, flags, fglob) + GetVnodeSummary(Cast(fglob.fg_data, 'vnode *'))
39236c6e 2666 count += 1
cb323159 2667 fpptr = kern.GetValueFromAddress(int(fpptr) + kern.ptrsize,'uint64_t *')
39236c6e
A
2668
2669@lldb_command('showallprocvnodes')
2670def ShowAllProcVnodes(cmd_args=None):
2671 """ Routine to print out all the open fds which are vnodes
2672 """
2673
2674 procptr = Cast(kern.globals.allproc.lh_first, 'proc *')
2675 while procptr and int(procptr) != 0:
2676 print '{:<s}'.format("=" * 106)
2677 print GetProcInfo(procptr)
2678 ShowProcVnodes([int(procptr)])
2679 procptr = procptr.p_list.le_next
2680
2681@xnudebug_test('test_vnode')
2682def TestShowAllVnodes(kernel_target, config, lldb_obj, isConnected ):
2683 """ Test the functionality of vnode related commands
5ba3f43e 2684 returns
39236c6e 2685 - False on failure
5ba3f43e 2686 - True on success
39236c6e
A
2687 """
2688 if not isConnected:
2689 print "Target is not connected. Cannot test memstats"
2690 return False
2691 res = lldb.SBCommandReturnObject()
2692 lldb_obj.debugger.GetCommandInterpreter().HandleCommand("showallvnodes", res)
2693 result = res.GetOutput()
2694 if len(result.split("\n")) > 2 and result.find('VREG') != -1 and len(result.splitlines()[2].split()) > 5:
2695 return True
5ba3f43e 2696 else:
39236c6e
A
2697 return False
2698
2699# Macro: showallmtx
2700@lldb_type_summary(['_lck_grp_ *'])
2701def GetMutexEntry(mtxg):
2702 """ Summarize a mutex group entry with important information.
2703 params:
2704 mtxg: value - obj representing a mutex group in kernel
2705 returns:
2706 out_string - summary of the mutex group
2707 """
2708 out_string = ""
2709
2710 if kern.ptrsize == 8:
2711 format_string = '{0:#018x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
2712 else:
2713 format_string = '{0:#010x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
2714
2715 if mtxg.lck_grp_mtxcnt:
2716 out_string += format_string.format(mtxg, mtxg.lck_grp_mtxcnt,mtxg.lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_util_cnt,
2717 mtxg.lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_miss_cnt,
2718 mtxg.lck_grp_stat.lck_grp_mtx_stat.lck_grp_mtx_wait_cnt, mtxg.lck_grp_name)
2719 return out_string
2720
2721@lldb_command('showallmtx')
2722def ShowAllMtx(cmd_args=None):
2723 """ Routine to print a summary listing of all mutexes
2724 """
2725
2726 if kern.ptrsize == 8:
2727 hdr_format = '{:<18s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
2728 else:
2729 hdr_format = '{:<10s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
5ba3f43e
A
2730
2731 print hdr_format.format('LCK GROUP', 'CNT', 'UTIL', 'MISS', 'WAIT', 'NAME')
39236c6e
A
2732
2733 mtxgrp_queue_head = kern.globals.lck_grp_queue
5ba3f43e
A
2734 mtxgrp_ptr_type = GetType('_lck_grp_ *')
2735
2736 for mtxgrp_ptr in IterateQueue(mtxgrp_queue_head, mtxgrp_ptr_type, "lck_grp_link"):
39236c6e
A
2737 print GetMutexEntry(mtxgrp_ptr)
2738 return
2739# EndMacro: showallmtx
2740
2741# Macro: showallrwlck
2742@lldb_type_summary(['_lck_grp_ *'])
2743def GetRWLEntry(rwlg):
2744 """ Summarize a reader writer lock group with important information.
2745 params:
2746 rwlg: value - obj representing a reader writer lock group in kernel
2747 returns:
2748 out_string - summary of the reader writer lock group
2749 """
2750 out_string = ""
2751
2752 if kern.ptrsize == 8:
2753 format_string = '{0:#018x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
2754 else:
2755 format_string = '{0:#010x} {1:10d} {2:10d} {3:10d} {4:10d} {5: <30s} '
2756
2757 if rwlg.lck_grp_rwcnt:
2758 out_string += format_string.format(rwlg, rwlg.lck_grp_rwcnt,rwlg.lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_util_cnt,
2759 rwlg.lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_miss_cnt,
2760 rwlg.lck_grp_stat.lck_grp_rw_stat.lck_grp_rw_wait_cnt, rwlg.lck_grp_name)
2761 return out_string
2762
15129b1c
A
2763#Macro: showlock
2764@lldb_type_summary(['lck_mtx_t *'])
2765@header("===== Mutex Lock Summary =====")
2766def GetMutexLockSummary(mtx):
2767 """ Summarize mutex lock with important information.
2768 params:
2769 mtx: value - obj representing a mutex lock in kernel
2770 returns:
2771 out_str - summary of the mutex lock
2772 """
2773 if not mtx:
2774 return "Invalid lock value: 0x0"
2775
2776 if kern.arch == "x86_64":
39037602
A
2777 out_str = "Lock Type : MUTEX\n"
2778 if mtx.lck_mtx_tag == 0x07ff1007 :
2779 out_str += "Tagged as indirect, printing ext lock at: {:#x}\n".format(mtx.lck_mtx_ptr)
2780 mtx = Cast(mtx.lck_mtx_ptr, 'lck_mtx_t *')
2781
2782 if mtx.lck_mtx_tag == 0x07fe2007 :
2783 out_str += "*** Tagged as DESTROYED ({:#x}) ***\n".format(mtx.lck_mtx_tag)
2784
2785 out_str += "Owner Thread : {mtx.lck_mtx_owner:#x}\n".format(mtx=mtx)
2786 out_str += "Number of Waiters : {mtx.lck_mtx_waiters:#x}\n".format(mtx=mtx)
2787 out_str += "ILocked : {mtx.lck_mtx_ilocked:#x}\n".format(mtx=mtx)
2788 out_str += "MLocked : {mtx.lck_mtx_mlocked:#x}\n".format(mtx=mtx)
2789 out_str += "Promoted : {mtx.lck_mtx_promoted:#x}\n".format(mtx=mtx)
2790 out_str += "Pri : {mtx.lck_mtx_pri:#x}\n".format(mtx=mtx)
2791 out_str += "Spin : {mtx.lck_mtx_spin:#x}\n".format(mtx=mtx)
2792 out_str += "Ext : {mtx.lck_mtx_is_ext:#x}\n".format(mtx=mtx)
d9a64523
A
2793 if mtx.lck_mtx_pad32 == 0xFFFFFFFF :
2794 out_str += "Canary (valid) : {mtx.lck_mtx_pad32:#x}\n".format(mtx=mtx)
39037602 2795 else:
d9a64523 2796 out_str += "Canary (INVALID) : {mtx.lck_mtx_pad32:#x}\n".format(mtx=mtx)
15129b1c
A
2797 return out_str
2798
2799 out_str = "Lock Type\t\t: MUTEX\n"
39037602
A
2800 out_str += "Owner Thread\t\t: {:#x}".format(mtx.lck_mtx_data & ~0x3)
2801 if (mtx.lck_mtx_data & ~0x3) == 0xfffffff0:
2802 out_str += " Held as spinlock"
2803 out_str += "\nNumber of Waiters\t: {:d}\n".format(mtx.lck_mtx_waiters)
15129b1c 2804 out_str += "Flags\t\t\t: "
39037602 2805 if mtx.lck_mtx_data & 0x1:
15129b1c 2806 out_str += "[Interlock Locked] "
39037602 2807 if mtx.lck_mtx_data & 0x2:
15129b1c 2808 out_str += "[Wait Flag]"
15129b1c
A
2809 return out_str
2810
2811@lldb_type_summary(['lck_spin_t *'])
2812@header("===== SpinLock Summary =====")
2813def GetSpinLockSummary(spinlock):
2814 """ Summarize spinlock with important information.
2815 params:
2816 spinlock: value - obj representing a spinlock in kernel
2817 returns:
2818 out_str - summary of the spinlock
2819 """
2820 if not spinlock:
2821 return "Invalid lock value: 0x0"
2822
2823 out_str = "Lock Type\t\t: SPINLOCK\n"
2824 if kern.arch == "x86_64":
2825 out_str += "Interlock\t\t: {:#x}\n".format(spinlock.interlock)
2826 return out_str
2827
39037602
A
2828 lock_data = spinlock.hwlock.lock_data
2829 if lock_data == 1:
2830 out_str += "Invalid state: interlock is locked but no owner\n"
2831 return out_str
2832 out_str += "Owner Thread\t\t: "
2833 if lock_data == 0:
2834 out_str += "None\n"
2835 else:
2836 out_str += "{:#x}\n".format(lock_data & ~0x1)
2837 if (lock_data & 1) == 0:
2838 out_str += "Invalid state: owned but interlock bit is not set\n"
15129b1c
A
2839 return out_str
2840
2841@lldb_command('showlock', 'MS')
2842def ShowLock(cmd_args=None, cmd_options={}):
2843 """ Show info about a lock - its state and owner thread details
2844 Usage: showlock <address of a lock>
2845 -M : to consider <addr> as lck_mtx_t
2846 -S : to consider <addr> as lck_spin_t
2847 """
2848 if not cmd_args:
2849 raise ArgumentError("Please specify the address of the lock whose info you want to view.")
2850 return
2851
2852 summary_str = ""
d9a64523
A
2853 addr = cmd_args[0]
2854 # from osfmk/arm/locks.h
2855 LCK_SPIN_TYPE = 0x11
2856 LCK_MTX_TYPE = 0x22
2857 if kern.arch == "x86_64":
15129b1c 2858 if "-M" in cmd_options:
d9a64523 2859 lock_mtx = kern.GetValueFromAddress(addr, 'lck_mtx_t *')
15129b1c
A
2860 summary_str = GetMutexLockSummary(lock_mtx)
2861 elif "-S" in cmd_options:
d9a64523 2862 lock_spin = kern.GetValueFromAddress(addr, 'lck_spin_t *')
15129b1c
A
2863 summary_str = GetSpinLockSummary(lock_spin)
2864 else:
2865 summary_str = "Please specify supported lock option(-M/-S)"
2866
2867 print summary_str
d9a64523
A
2868 else:
2869 lock = kern.GetValueFromAddress(addr, 'uintptr_t *')
2870 if lock:
2871 lock_mtx = Cast(lock, 'lck_mtx_t*')
2872 if lock_mtx.lck_mtx_type == LCK_MTX_TYPE:
2873 summary_str = GetMutexLockSummary(lock_mtx)
2874
2875 lock_spin = Cast(lock, 'lck_spin_t*')
2876 if lock_spin.type == LCK_SPIN_TYPE:
2877 summary_str = GetSpinLockSummary(lock_spin)
2878 if summary_str == "":
2879 summary_str = "Lock Type\t\t: INVALID LOCK"
2880 print summary_str
15129b1c
A
2881
2882#EndMacro: showlock
2883
39236c6e
A
2884@lldb_command('showallrwlck')
2885def ShowAllRWLck(cmd_args=None):
2886 """ Routine to print a summary listing of all read/writer locks
2887 """
2888 if kern.ptrsize == 8:
2889 hdr_format = '{:<18s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
2890 else:
2891 hdr_format = '{:<10s} {:>10s} {:>10s} {:>10s} {:>10s} {:<30s} '
2892
2893 print hdr_format.format('LCK GROUP', 'CNT', 'UTIL', 'MISS', 'WAIT', 'NAME')
2894
2895 rwlgrp_queue_head = kern.globals.lck_grp_queue
2896 rwlgrp_ptr_type = GetType('_lck_grp_ *')
2897 for rwlgrp_ptr in IterateQueue(rwlgrp_queue_head, rwlgrp_ptr_type, "lck_grp_link"):
2898 print GetRWLEntry(rwlgrp_ptr)
2899 return
2900# EndMacro: showallrwlck
2901
2902#Macro: showbootermemorymap
2903@lldb_command('showbootermemorymap')
2904def ShowBooterMemoryMap(cmd_args=None):
2905 """ Prints out the phys memory map from kernelBootArgs
2906 Supported only on x86_64
2907 """
5ba3f43e 2908 if kern.arch != 'x86_64':
39236c6e
A
2909 print "showbootermemorymap not supported on this architecture"
2910 return
5ba3f43e 2911
39236c6e
A
2912 out_string = ""
2913
2914 # Memory type map
2915 memtype_dict = {
2916 0: 'Reserved',
2917 1: 'LoaderCode',
2918 2: 'LoaderData',
2919 3: 'BS_code',
2920 4: 'BS_data',
2921 5: 'RT_code',
2922 6: 'RT_data',
2923 7: 'Convention',
2924 8: 'Unusable',
2925 9: 'ACPI_recl',
2926 10: 'ACPI_NVS',
2927 11: 'MemMapIO',
2928 12: 'MemPortIO',
2929 13: 'PAL_code'
2930 }
2931
2932 boot_args = kern.globals.kernelBootArgs
2933 msize = boot_args.MemoryMapDescriptorSize
2934 mcount = (boot_args.MemoryMapSize) / unsigned(msize)
2935
2936 out_string += "{0: <12s} {1: <19s} {2: <19s} {3: <19s} {4: <10s}\n".format("Type", "Physical Start", "Number of Pages", "Virtual Start", "Attributes")
2937
2938 i = 0
2939 while i < mcount:
5ba3f43e 2940 mptr = kern.GetValueFromAddress(unsigned(boot_args.MemoryMap) + kern.VM_MIN_KERNEL_ADDRESS + unsigned(i*msize), 'EfiMemoryRange *')
39236c6e
A
2941 mtype = unsigned(mptr.Type)
2942 if mtype in memtype_dict:
2943 out_string += "{0: <12s}".format(memtype_dict[mtype])
2944 else:
2945 out_string += "{0: <12s}".format("UNKNOWN")
2946
2947 if mptr.VirtualStart == 0:
2948 out_string += "{0: #019x} {1: #019x} {2: <19s} {3: #019x}\n".format(mptr.PhysicalStart, mptr.NumberOfPages, ' '*19, mptr.Attribute)
2949 else:
2950 out_string += "{0: #019x} {1: #019x} {2: #019x} {3: #019x}\n".format(mptr.PhysicalStart, mptr.NumberOfPages, mptr.VirtualStart, mptr.Attribute)
2951 i = i + 1
2952
2953 print out_string
2954#EndMacro: showbootermemorymap
2955
fe8ab488
A
2956@lldb_command('show_all_purgeable_objects')
2957def ShowAllPurgeableVmObjects(cmd_args=None):
2958 """ Routine to print a summary listing of all the purgeable vm objects
2959 """
2960 print "\n-------------------- VOLATILE OBJECTS --------------------\n"
2961 ShowAllPurgeableVolatileVmObjects()
2962 print "\n-------------------- NON-VOLATILE OBJECTS --------------------\n"
2963 ShowAllPurgeableNonVolatileVmObjects()
2964
2965@lldb_command('show_all_purgeable_nonvolatile_objects')
2966def ShowAllPurgeableNonVolatileVmObjects(cmd_args=None):
2967 """ Routine to print a summary listing of all the vm objects in
2968 the purgeable_nonvolatile_queue
2969 """
2970
2971 nonvolatile_total = lambda:None
2972 nonvolatile_total.objects = 0
2973 nonvolatile_total.vsize = 0
2974 nonvolatile_total.rsize = 0
2975 nonvolatile_total.wsize = 0
2976 nonvolatile_total.csize = 0
2977 nonvolatile_total.disowned_objects = 0
2978 nonvolatile_total.disowned_vsize = 0
2979 nonvolatile_total.disowned_rsize = 0
2980 nonvolatile_total.disowned_wsize = 0
2981 nonvolatile_total.disowned_csize = 0
2982
2983 queue_len = kern.globals.purgeable_nonvolatile_count
2984 queue_head = kern.globals.purgeable_nonvolatile_queue
2985
d9a64523 2986 print 'purgeable_nonvolatile_queue:{: <#018x} purgeable_volatile_count:{:d}\n'.format(kern.GetLoadAddressForSymbol('purgeable_nonvolatile_queue'),queue_len)
fe8ab488
A
2987 print 'N:non-volatile V:volatile E:empty D:deny\n'
2988
d9a64523 2989 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")
fe8ab488
A
2990 idx = 0
2991 for object in IterateQueue(queue_head, 'struct vm_object *', 'objq'):
2992 idx += 1
2993 ShowPurgeableNonVolatileVmObject(object, idx, queue_len, nonvolatile_total)
2994 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)
2995 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)
2996
2997
2998def ShowPurgeableNonVolatileVmObject(object, idx, queue_len, nonvolatile_total):
2999 """ Routine to print out a summary a VM object in purgeable_nonvolatile_queue
3000 params:
3001 object - core.value : a object of type 'struct vm_object *'
3002 returns:
3003 None
3004 """
3e170ce0 3005 page_size = kern.globals.page_size
fe8ab488
A
3006 if object.purgable == 0:
3007 purgable = "N"
3008 elif object.purgable == 1:
3009 purgable = "V"
3010 elif object.purgable == 2:
3011 purgable = "E"
3012 elif object.purgable == 3:
3013 purgable = "D"
3014 else:
3015 purgable = "?"
3016 if object.pager == 0:
3017 compressed_count = 0
3018 else:
3019 compressor_pager = Cast(object.pager, 'compressor_pager *')
3020 compressed_count = compressor_pager.cpgr_num_slots_occupied
3021
d9a64523 3022 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))
fe8ab488
A
3023
3024 nonvolatile_total.objects += 1
3e170ce0 3025 nonvolatile_total.vsize += object.vo_un1.vou_size/page_size
fe8ab488
A
3026 nonvolatile_total.rsize += object.resident_page_count
3027 nonvolatile_total.wsize += object.wired_page_count
3028 nonvolatile_total.csize += compressed_count
d9a64523 3029 if object.vo_un2.vou_owner == 0:
fe8ab488 3030 nonvolatile_total.disowned_objects += 1
3e170ce0 3031 nonvolatile_total.disowned_vsize += object.vo_un1.vou_size/page_size
fe8ab488
A
3032 nonvolatile_total.disowned_rsize += object.resident_page_count
3033 nonvolatile_total.disowned_wsize += object.wired_page_count
3034 nonvolatile_total.disowned_csize += compressed_count
3035
3036
3037@lldb_command('show_all_purgeable_volatile_objects')
3038def ShowAllPurgeableVolatileVmObjects(cmd_args=None):
3039 """ Routine to print a summary listing of all the vm objects in
3040 the purgeable queues
3041 """
3042 volatile_total = lambda:None
3043 volatile_total.objects = 0
3044 volatile_total.vsize = 0
3045 volatile_total.rsize = 0
3046 volatile_total.wsize = 0
3047 volatile_total.csize = 0
3048 volatile_total.disowned_objects = 0
3049 volatile_total.disowned_vsize = 0
3050 volatile_total.disowned_rsize = 0
3051 volatile_total.disowned_wsize = 0
3052 volatile_total.disowned_csize = 0
3053
3054 purgeable_queues = kern.globals.purgeable_queues
3055 print "---------- OBSOLETE\n"
3056 ShowPurgeableQueue(purgeable_queues[0], volatile_total)
3057 print "\n\n---------- FIFO\n"
3058 ShowPurgeableQueue(purgeable_queues[1], volatile_total)
3059 print "\n\n---------- LIFO\n"
3060 ShowPurgeableQueue(purgeable_queues[2], volatile_total)
3061
3062 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)
3063 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)
3064 purgeable_count = kern.globals.vm_page_purgeable_count
3065 purgeable_wired_count = kern.globals.vm_page_purgeable_wired_count
3066 if purgeable_count != volatile_total.rsize or purgeable_wired_count != volatile_total.wsize:
3067 mismatch = "<--------- MISMATCH\n"
3068 else:
3069 mismatch = ""
3070 print "vm_page_purgeable_count: resident:{:<10d} wired:{:<10d} {:s}\n".format(purgeable_count, purgeable_wired_count, mismatch)
3071
3072
3073def ShowPurgeableQueue(qhead, volatile_total):
3074 print "----- GROUP 0\n"
3075 ShowPurgeableGroup(qhead.objq[0], volatile_total)
3076 print "----- GROUP 1\n"
3077 ShowPurgeableGroup(qhead.objq[1], volatile_total)
3078 print "----- GROUP 2\n"
3079 ShowPurgeableGroup(qhead.objq[2], volatile_total)
3080 print "----- GROUP 3\n"
3081 ShowPurgeableGroup(qhead.objq[3], volatile_total)
3082 print "----- GROUP 4\n"
3083 ShowPurgeableGroup(qhead.objq[4], volatile_total)
3084 print "----- GROUP 5\n"
3085 ShowPurgeableGroup(qhead.objq[5], volatile_total)
3086 print "----- GROUP 6\n"
3087 ShowPurgeableGroup(qhead.objq[6], volatile_total)
3088 print "----- GROUP 7\n"
3089 ShowPurgeableGroup(qhead.objq[7], volatile_total)
3090
3091def ShowPurgeableGroup(qhead, volatile_total):
3092 idx = 0
3093 for object in IterateQueue(qhead, 'struct vm_object *', 'objq'):
3094 if idx == 0:
3095# 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","")
d9a64523 3096 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")
fe8ab488
A
3097 idx += 1
3098 ShowPurgeableVolatileVmObject(object, idx, volatile_total)
3099
3100def ShowPurgeableVolatileVmObject(object, idx, volatile_total):
3101 """ Routine to print out a summary a VM object in a purgeable queue
3102 params:
3103 object - core.value : a object of type 'struct vm_object *'
3104 returns:
3105 None
3106 """
d9a64523 3107## if int(object.vo_un2.vou_owner) != int(object.vo_purgeable_volatilizer):
fe8ab488 3108# diff=" !="
5ba3f43e 3109## else:
fe8ab488 3110# diff=" "
3e170ce0 3111 page_size = kern.globals.page_size
fe8ab488
A
3112 if object.purgable == 0:
3113 purgable = "N"
3114 elif object.purgable == 1:
3115 purgable = "V"
3116 elif object.purgable == 2:
3117 purgable = "E"
3118 elif object.purgable == 3:
3119 purgable = "D"
3120 else:
3121 purgable = "?"
3122 if object.pager == 0:
3123 compressed_count = 0
3124 else:
3125 compressor_pager = Cast(object.pager, 'compressor_pager *')
3126 compressed_count = compressor_pager.cpgr_num_slots_occupied
d9a64523
A
3127# 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)
3128 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))
fe8ab488 3129 volatile_total.objects += 1
3e170ce0 3130 volatile_total.vsize += object.vo_un1.vou_size/page_size
fe8ab488
A
3131 volatile_total.rsize += object.resident_page_count
3132 volatile_total.wsize += object.wired_page_count
3133 volatile_total.csize += compressed_count
d9a64523 3134 if object.vo_un2.vou_owner == 0:
fe8ab488 3135 volatile_total.disowned_objects += 1
3e170ce0 3136 volatile_total.disowned_vsize += object.vo_un1.vou_size/page_size
fe8ab488
A
3137 volatile_total.disowned_rsize += object.resident_page_count
3138 volatile_total.disowned_wsize += object.wired_page_count
3139 volatile_total.disowned_csize += compressed_count
3140
3141
3142def GetCompressedPagesForObject(obj):
3143 """Stuff
3144 """
3145 pager = Cast(obj.pager, 'compressor_pager_t')
3146 return pager.cpgr_num_slots_occupied
5ba3f43e
A
3147 """ # commented code below
3148 if pager.cpgr_num_slots > 128:
3149 slots_arr = pager.cpgr_slots.cpgr_islots
3150 num_indirect_slot_ptr = (pager.cpgr_num_slots + 127) / 128
3151 index = 0
3152 compressor_slot = 0
3153 compressed_pages = 0
3154 while index < num_indirect_slot_ptr:
3155 compressor_slot = 0
3156 if slots_arr[index]:
3157 while compressor_slot < 128:
3158 if slots_arr[index][compressor_slot]:
3159 compressed_pages += 1
3160 compressor_slot += 1
3161 index += 1
3162 else:
3163 slots_arr = pager.cpgr_slots.cpgr_dslots
3164 compressor_slot = 0
3165 compressed_pages = 0
3166 while compressor_slot < pager.cpgr_num_slots:
3167 if slots_arr[compressor_slot]:
3168 compressed_pages += 1
3169 compressor_slot += 1
3170 return compressed_pages
3171 """
fe8ab488 3172
fe8ab488
A
3173def ShowTaskVMEntries(task, show_pager_info, show_all_shadows):
3174 """ Routine to print out a summary listing of all the entries in a vm_map
3175 params:
3176 task - core.value : a object of type 'task *'
3177 returns:
3178 None
3179 """
3180 print "vm_map entries for task " + hex(task)
3181 print GetTaskSummary.header
3182 print GetTaskSummary(task)
3183 if not task.map:
3184 print "Task {0: <#020x} has map = 0x0"
3185 return None
d9a64523 3186 showmapvme(task.map, 0, 0, show_pager_info, show_all_shadows, False)
fe8ab488 3187
94ff46dc 3188@lldb_command("showmapvme", "A:B:F:PRST")
fe8ab488
A
3189def ShowMapVME(cmd_args=None, cmd_options={}):
3190 """Routine to print out info about the specified vm_map and its vm entries
d9a64523
A
3191 usage: showmapvme <vm_map> [-A start] [-B end] [-S] [-P]
3192 Use -A <start> flag to start at virtual address <start>
3193 Use -B <end> flag to end at virtual address <end>
94ff46dc 3194 Use -F <virtaddr> flag to find just the VME containing the given VA
3e170ce0
A
3195 Use -S flag to show VM object shadow chains
3196 Use -P flag to show pager info (mapped file, compressed pages, ...)
d9a64523
A
3197 Use -R flag to reverse order
3198 Use -T to show red-black tree pointers
fe8ab488
A
3199 """
3200 if cmd_args == None or len(cmd_args) < 1:
d9a64523 3201 print "Invalid argument.", ShowMapVME.__doc__
fe8ab488
A
3202 return
3203 show_pager_info = False
3204 show_all_shadows = False
d9a64523
A
3205 show_rb_tree = False
3206 start_vaddr = 0
3207 end_vaddr = 0
3208 reverse_order = False
3209 if "-A" in cmd_options:
3210 start_vaddr = unsigned(int(cmd_options['-A'], 16))
3211 if "-B" in cmd_options:
3212 end_vaddr = unsigned(int(cmd_options['-B'], 16))
94ff46dc
A
3213 if "-F" in cmd_options:
3214 start_vaddr = unsigned(int(cmd_options['-F'], 16))
3215 end_vaddr = start_vaddr
fe8ab488
A
3216 if "-P" in cmd_options:
3217 show_pager_info = True
3218 if "-S" in cmd_options:
3219 show_all_shadows = True
d9a64523
A
3220 if "-R" in cmd_options:
3221 reverse_order = True
3222 if "-T" in cmd_options:
3223 show_rb_tree = True
fe8ab488 3224 map = kern.GetValueFromAddress(cmd_args[0], 'vm_map_t')
d9a64523
A
3225 showmapvme(map, start_vaddr, end_vaddr, show_pager_info, show_all_shadows, reverse_order, show_rb_tree)
3226
f427ee49
A
3227@lldb_command("showmapcopyvme", "A:B:F:PRST")
3228def ShowMapCopyVME(cmd_args=None, cmd_options={}):
3229 """Routine to print out info about the specified vm_map_copy and its vm entries
3230 usage: showmapcopyvme <vm_map_copy> [-A start] [-B end] [-S] [-P]
3231 Use -A <start> flag to start at virtual address <start>
3232 Use -B <end> flag to end at virtual address <end>
3233 Use -F <virtaddr> flag to find just the VME containing the given VA
3234 Use -S flag to show VM object shadow chains
3235 Use -P flag to show pager info (mapped file, compressed pages, ...)
3236 Use -R flag to reverse order
3237 Use -T to show red-black tree pointers
3238 """
3239 if cmd_args == None or len(cmd_args) < 1:
3240 print "Invalid argument.", ShowMapVME.__doc__
3241 return
3242 show_pager_info = False
3243 show_all_shadows = False
3244 show_rb_tree = False
3245 start_vaddr = 0
3246 end_vaddr = 0
3247 reverse_order = False
3248 if "-A" in cmd_options:
3249 start_vaddr = unsigned(int(cmd_options['-A'], 16))
3250 if "-B" in cmd_options:
3251 end_vaddr = unsigned(int(cmd_options['-B'], 16))
3252 if "-F" in cmd_options:
3253 start_vaddr = unsigned(int(cmd_options['-F'], 16))
3254 end_vaddr = start_vaddr
3255 if "-P" in cmd_options:
3256 show_pager_info = True
3257 if "-S" in cmd_options:
3258 show_all_shadows = True
3259 if "-R" in cmd_options:
3260 reverse_order = True
3261 if "-T" in cmd_options:
3262 show_rb_tree = True
3263 map = kern.GetValueFromAddress(cmd_args[0], 'vm_map_copy_t')
3264 showmapcopyvme(map, start_vaddr, end_vaddr, show_pager_info, show_all_shadows, reverse_order, show_rb_tree)
3265
d9a64523
A
3266@lldb_command("showvmobject", "A:B:PRST")
3267def ShowVMObject(cmd_args=None, cmd_options={}):
3268 """Routine to print out a VM object and its shadow chain
3269 usage: showvmobject <vm_object> [-S] [-P]
3270 -S: show VM object shadow chain
3271 -P: show pager info (mapped file, compressed pages, ...)
3272 """
3273 if cmd_args == None or len(cmd_args) < 1:
3274 print "Invalid argument.", ShowMapVME.__doc__
3275 return
3276 show_pager_info = False
3277 show_all_shadows = False
3278 if "-P" in cmd_options:
3279 show_pager_info = True
3280 if "-S" in cmd_options:
3281 show_all_shadows = True
3282 object = kern.GetValueFromAddress(cmd_args[0], 'vm_object_t')
3283 showvmobject(object, 0, 0, show_pager_info, show_all_shadows)
fe8ab488 3284
d9a64523 3285def showvmobject(object, offset=0, size=0, show_pager_info=False, show_all_shadows=False):
3e170ce0 3286 page_size = kern.globals.page_size
fe8ab488
A
3287 vnode_pager_ops = kern.globals.vnode_pager_ops
3288 vnode_pager_ops_addr = unsigned(addressof(vnode_pager_ops))
d9a64523
A
3289 depth = 0
3290 if size == 0 and object != 0 and object.internal:
3291 size = object.vo_un1.vou_size
3292 while object != 0:
3293 depth += 1
3294 if show_all_shadows == False and depth != 1 and object.shadow != 0:
3295 offset += unsigned(object.vo_un2.vou_shadow_offset)
3296 object = object.shadow
3297 continue
3298 if object.copy_strategy == 0:
3299 copy_strategy="N"
3300 elif object.copy_strategy == 2:
3301 copy_strategy="D"
3302 elif object.copy_strategy == 4:
3303 copy_strategy="S"
3304
3305 else:
3306 copy_strategy=str(object.copy_strategy)
3307 if object.internal:
3308 internal = "internal"
3309 else:
3310 internal = "external"
3311 purgeable = "NVED"[int(object.purgable)]
3312 pager_string = ""
3313 if object.phys_contiguous:
3314 pager_string = pager_string + "phys_contig {:#018x}:{:#018x} ".format(unsigned(object.vo_un2.vou_shadow_offset), unsigned(object.vo_un1.vou_size))
3315 pager = object.pager
3316 if show_pager_info and pager != 0:
3317 if object.internal:
3318 pager_string = pager_string + "-> compressed:{:d}".format(GetCompressedPagesForObject(object))
3319 elif unsigned(pager.mo_pager_ops) == vnode_pager_ops_addr:
3320 vnode_pager = Cast(pager,'vnode_pager *')
3321 pager_string = pager_string + "-> " + GetVnodePath(vnode_pager.vnode_handle)
3322 else:
3323 pager_string = pager_string + "-> {:s}:{: <#018x}".format(pager.mo_pager_ops.memory_object_pager_name, pager)
3324 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)
3325# 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)
3326 offset += unsigned(object.vo_un2.vou_shadow_offset)
3327 object = object.shadow
3328
3329def showmapvme(map, start_vaddr, end_vaddr, show_pager_info, show_all_shadows, reverse_order=False, show_rb_tree=False):
fe8ab488
A
3330 rsize = 0
3331 if map.pmap != 0:
3332 rsize = int(map.pmap.stats.resident_count)
f427ee49
A
3333 print "{:<18s} {:<18s} {:<18s} {:>10s} {:>18s} {:>18s}:{:<18s} {:<7s}".format("vm_map","pmap","size","#ents","rsize","start","end","pgshift")
3334 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)
d9a64523
A
3335 showmaphdrvme(map.hdr, map.pmap, start_vaddr, end_vaddr, show_pager_info, show_all_shadows, reverse_order, show_rb_tree)
3336
3337def showmapcopyvme(mapcopy, start_vaddr=0, end_vaddr=0, show_pager_info=True, show_all_shadows=True, reverse_order=False, show_rb_tree=False):
f427ee49
A
3338 print "{:<18s} {:<18s} {:<18s} {:>10s} {:>18s} {:>18s}:{:<18s} {:<7s}".format("vm_map_copy","offset","size","#ents","rsize","start","end","pgshift")
3339 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)
d9a64523
A
3340 showmaphdrvme(mapcopy.c_u.hdr, 0, start_vaddr, end_vaddr, show_pager_info, show_all_shadows, reverse_order, show_rb_tree)
3341
3342def showmaphdrvme(maphdr, pmap, start_vaddr, end_vaddr, show_pager_info, show_all_shadows, reverse_order, show_rb_tree):
3343 page_size = kern.globals.page_size
3344 vnode_pager_ops = kern.globals.vnode_pager_ops
3345 vnode_pager_ops_addr = unsigned(addressof(vnode_pager_ops))
3346 if hasattr(kern.globals, 'compressor_object'):
3347 compressor_object = kern.globals.compressor_object
3348 else:
3349 compressor_object = -1;
3350 vme_list_head = maphdr.links
fe8ab488 3351 vme_ptr_type = GetType('vm_map_entry *')
d9a64523
A
3352 print "{:<18s} {:>18s}:{:<18s} {:>10s} {:<8s} {:<16s} {:<18s} {:<18s}".format("entry","start","end","#pgs","tag.kmod","prot&flags","object","offset")
3353 last_end = unsigned(maphdr.links.start)
3354 skipped_entries = 0
3355 for vme in IterateQueue(vme_list_head, vme_ptr_type, "links", reverse_order):
3356 if start_vaddr != 0 and end_vaddr != 0:
3357 if unsigned(vme.links.start) > end_vaddr:
3358 break
3359 if unsigned(vme.links.end) <= start_vaddr:
3360 last_end = unsigned(vme.links.end)
3361 skipped_entries = skipped_entries + 1
3362 continue
3363 if skipped_entries != 0:
3364 print "... skipped {:d} entries ...".format(skipped_entries)
3365 skipped_entries = 0
3e170ce0
A
3366 if unsigned(vme.links.start) != last_end:
3367 print "{:18s} {:#018x}:{:#018x} {:>10d}".format("------------------",last_end,vme.links.start,(unsigned(vme.links.start) - last_end)/page_size)
3368 last_end = unsigned(vme.links.end)
3369 size = unsigned(vme.links.end) - unsigned(vme.links.start)
3370 object = vme.vme_object.vmo_object
3371 if object == 0:
d9a64523 3372 object_str = "{: <#018x}".format(object)
3e170ce0
A
3373 elif vme.is_sub_map:
3374 if object == kern.globals.bufferhdr_map:
3375 object_str = "BUFFERHDR_MAP"
3376 elif object == kern.globals.mb_map:
3377 object_str = "MB_MAP"
3378 elif object == kern.globals.bsd_pageable_map:
3379 object_str = "BSD_PAGEABLE_MAP"
3380 elif object == kern.globals.ipc_kernel_map:
3381 object_str = "IPC_KERNEL_MAP"
3382 elif object == kern.globals.ipc_kernel_copy_map:
3383 object_str = "IPC_KERNEL_COPY_MAP"
3384 elif object == kern.globals.kalloc_map:
3385 object_str = "KALLOC_MAP"
39037602
A
3386 elif hasattr(kern.globals, 'compressor_map') and object == kern.globals.compressor_map:
3387 object_str = "COMPRESSOR_MAP"
3e170ce0
A
3388 elif hasattr(kern.globals, 'gzalloc_map') and object == kern.globals.gzalloc_map:
3389 object_str = "GZALLOC_MAP"
3390 elif hasattr(kern.globals, 'g_kext_map') and object == kern.globals.g_kext_map:
3391 object_str = "G_KEXT_MAP"
3392 elif hasattr(kern.globals, 'vector_upl_submap') and object == kern.globals.vector_upl_submap:
3393 object_str = "VECTOR_UPL_SUBMAP"
3394 else:
d9a64523 3395 object_str = "submap:{: <#018x}".format(object)
3e170ce0
A
3396 else:
3397 if object == kern.globals.kernel_object:
3398 object_str = "KERNEL_OBJECT"
3399 elif object == kern.globals.vm_submap_object:
3400 object_str = "VM_SUBMAP_OBJECT"
d9a64523 3401 elif object == compressor_object:
3e170ce0
A
3402 object_str = "COMPRESSOR_OBJECT"
3403 else:
d9a64523 3404 object_str = "{: <#018x}".format(object)
3e170ce0
A
3405 offset = unsigned(vme.vme_offset) & ~0xFFF
3406 tag = unsigned(vme.vme_offset & 0xFFF)
d9a64523
A
3407 protection = ""
3408 if vme.protection & 0x1:
3409 protection +="r"
3410 else:
3411 protection += "-"
3412 if vme.protection & 0x2:
3413 protection += "w"
3414 else:
3415 protection += "-"
3416 if vme.protection & 0x4:
3417 protection += "x"
3418 else:
3419 protection += "-"
3420 max_protection = ""
3421 if vme.max_protection & 0x1:
3422 max_protection +="r"
3423 else:
3424 max_protection += "-"
3425 if vme.max_protection & 0x2:
3426 max_protection += "w"
3427 else:
3428 max_protection += "-"
3429 if vme.max_protection & 0x4:
3430 max_protection += "x"
3431 else:
3432 max_protection += "-"
fe8ab488
A
3433 vme_flags = ""
3434 if vme.is_sub_map:
3435 vme_flags += "s"
3e170ce0
A
3436 if vme.needs_copy:
3437 vme_flags += "n"
d9a64523 3438 if vme.use_pmap:
3e170ce0 3439 vme_flags += "p"
d9a64523
A
3440 if vme.wired_count:
3441 vme_flags += "w"
3442 if vme.used_for_jit:
3443 vme_flags += "j"
3e170ce0 3444 tagstr = ""
d9a64523 3445 if pmap == kern.globals.kernel_pmap:
3e170ce0 3446 xsite = Cast(kern.globals.vm_allocation_sites[tag],'OSKextAccount *')
5ba3f43e 3447 if xsite and xsite.site.flags & 0x0200:
3e170ce0 3448 tagstr = ".{:<3d}".format(xsite.loadTag)
d9a64523
A
3449 rb_info = ""
3450 if show_rb_tree:
3451 rb_info = "l={: <#018x} r={: <#018x} p={: <#018x}".format(vme.store.entry.rbe_left, vme.store.entry.rbe_right, vme.store.entry.rbe_parent)
3452 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)
3e170ce0
A
3453 if (show_pager_info or show_all_shadows) and vme.is_sub_map == 0 and vme.vme_object.vmo_object != 0:
3454 object = vme.vme_object.vmo_object
fe8ab488
A
3455 else:
3456 object = 0
d9a64523
A
3457 showvmobject(object, offset, size, show_pager_info, show_all_shadows)
3458 if start_vaddr != 0 or end_vaddr != 0:
3459 print "..."
3460 elif unsigned(maphdr.links.end) > last_end:
3461 print "{:18s} {:#018x}:{:#018x} {:>10d}".format("------------------",last_end,maphdr.links.end,(unsigned(maphdr.links.end) - last_end)/page_size)
fe8ab488
A
3462 return None
3463
3e170ce0
A
3464def CountMapTags(map, tagcounts, slow):
3465 page_size = unsigned(kern.globals.page_size)
3466 vme_list_head = map.hdr.links
3467 vme_ptr_type = GetType('vm_map_entry *')
3468 for vme in IterateQueue(vme_list_head, vme_ptr_type, "links"):
3469 object = vme.vme_object.vmo_object
3470 tag = vme.vme_offset & 0xFFF
3471 if object == kern.globals.kernel_object:
3472 count = 0
3473 if not slow:
3474 count = unsigned(vme.links.end - vme.links.start) / page_size
3475 else:
3476 addr = unsigned(vme.links.start)
3477 while addr < unsigned(vme.links.end):
3478 hash_id = _calc_vm_page_hash(object, addr)
3479 page_list = kern.globals.vm_page_buckets[hash_id].page_list
3480 page = _vm_page_unpack_ptr(page_list)
3481 while (page != 0):
3482 vmpage = kern.GetValueFromAddress(page, 'vm_page_t')
d9a64523
A
3483 if (addr == unsigned(vmpage.vmp_offset)) and (object == vm_object_t(_vm_page_unpack_ptr(vmpage.vmp_object))):
3484 if (not vmpage.vmp_local) and (vmpage.vmp_wire_count > 0):
3e170ce0
A
3485 count += 1
3486 break
d9a64523 3487 page = _vm_page_unpack_ptr(vmpage.vmp_next_m)
3e170ce0
A
3488 addr += page_size
3489 tagcounts[tag] += count
3490 elif vme.is_sub_map:
3491 CountMapTags(Cast(object,'vm_map_t'), tagcounts, slow)
3492 return None
3493
3494def CountWiredObject(object, tagcounts):
3495 tagcounts[unsigned(object.wire_tag)] += object.wired_page_count
3496 return None
3497
3e170ce0
A
3498def GetKmodIDName(kmod_id):
3499 kmod_val = kern.globals.kmod
3500 for kmod in IterateLinkedList(kmod_val, 'next'):
3501 if (kmod.id == kmod_id):
3502 return "{:<50s}".format(kmod.name)
3503 return "??"
3504
5ba3f43e
A
3505FixedTags = {
3506 0: "VM_KERN_MEMORY_NONE",
3507 1: "VM_KERN_MEMORY_OSFMK",
3508 2: "VM_KERN_MEMORY_BSD",
3509 3: "VM_KERN_MEMORY_IOKIT",
3510 4: "VM_KERN_MEMORY_LIBKERN",
3511 5: "VM_KERN_MEMORY_OSKEXT",
3512 6: "VM_KERN_MEMORY_KEXT",
3513 7: "VM_KERN_MEMORY_IPC",
3514 8: "VM_KERN_MEMORY_STACK",
3515 9: "VM_KERN_MEMORY_CPU",
3516 10: "VM_KERN_MEMORY_PMAP",
3517 11: "VM_KERN_MEMORY_PTE",
3518 12: "VM_KERN_MEMORY_ZONE",
3519 13: "VM_KERN_MEMORY_KALLOC",
3520 14: "VM_KERN_MEMORY_COMPRESSOR",
3521 15: "VM_KERN_MEMORY_COMPRESSED_DATA",
3522 16: "VM_KERN_MEMORY_PHANTOM_CACHE",
3523 17: "VM_KERN_MEMORY_WAITQ",
3524 18: "VM_KERN_MEMORY_DIAG",
3525 19: "VM_KERN_MEMORY_LOG",
3526 20: "VM_KERN_MEMORY_FILE",
3527 21: "VM_KERN_MEMORY_MBUF",
3528 22: "VM_KERN_MEMORY_UBC",
3529 23: "VM_KERN_MEMORY_SECURITY",
3530 24: "VM_KERN_MEMORY_MLOCK",
3531 25: "VM_KERN_MEMORY_REASON",
3532 26: "VM_KERN_MEMORY_SKYWALK",
3533 27: "VM_KERN_MEMORY_LTABLE",
f427ee49 3534 28: "VM_KERN_MEMORY_HV",
c3c9b80d 3535 29: "VM_KERN_MEMORY_RETIRED",
5ba3f43e
A
3536 255:"VM_KERN_MEMORY_ANY",
3537}
3e170ce0 3538
5ba3f43e 3539def GetVMKernName(tag):
cb323159
A
3540 """ returns the formatted name for a vmtag and
3541 the sub-tag for kmod tags.
3542 """
3543 if ((tag <= 27) or (tag == 255)):
3544 return (FixedTags[tag], "")
3545 site = kern.globals.vm_allocation_sites[tag]
3546 if site:
3547 if site.flags & 0x007F:
3548 cstr = addressof(site.subtotals[site.subtotalscount])
3549 return ("{:<50s}".format(str(Cast(cstr, 'char *'))), "")
3550 else:
3551 if site.flags & 0x0200:
3552 xsite = Cast(site,'OSKextAccount *')
3553 tagstr = ".{:<3d}".format(xsite.loadTag)
3554 return (GetKmodIDName(xsite.loadTag), tagstr);
3555 else:
3556 return (kern.Symbolicate(site), "")
3557 return ("", "")
3e170ce0 3558
c3c9b80d 3559@lldb_command("showvmtags", "ASJO")
3e170ce0
A
3560def showvmtags(cmd_args=None, cmd_options={}):
3561 """Routine to print out info about kernel wired page allocations
3562 usage: showvmtags
3563 iterates kernel map and vm objects totaling allocations by tag.
c3c9b80d 3564 usage: showvmtags -S [-O]
3e170ce0 3565 also iterates kernel object pages individually - slow.
c3c9b80d 3566 usage: showvmtags -A [-O]
d9a64523 3567 show all tags, even tags that have no wired count
c3c9b80d 3568 usage: showvmtags -J [-O]
f427ee49 3569 Output json
c3c9b80d
A
3570
3571 -O: list in increasing size order
3e170ce0
A
3572 """
3573 slow = False
f427ee49 3574 print_json = False
3e170ce0
A
3575 if "-S" in cmd_options:
3576 slow = True
d9a64523
A
3577 all_tags = False
3578 if "-A" in cmd_options:
3579 all_tags = True
f427ee49
A
3580 if "-J" in cmd_options:
3581 print_json = True
3582
3e170ce0 3583 page_size = unsigned(kern.globals.page_size)
94ff46dc 3584 nsites = unsigned(kern.globals.vm_allocation_tag_highest) + 1
cb323159 3585 tagcounts = [0] * nsites
cb323159 3586 tagmapped = [0] * nsites
5ba3f43e
A
3587
3588 if kern.globals.vm_tag_active_update:
cb323159 3589 for tag in range(nsites):
5ba3f43e
A
3590 site = kern.globals.vm_allocation_sites[tag]
3591 if site:
cb323159
A
3592 tagcounts[tag] = unsigned(site.total)
3593 tagmapped[tag] = unsigned(site.mapped)
5ba3f43e
A
3594 else:
3595 queue_head = kern.globals.vm_objects_wired
d9a64523 3596 for object in IterateQueue(queue_head, 'struct vm_object *', 'wired_objq'):
5ba3f43e
A
3597 if object != kern.globals.kernel_object:
3598 CountWiredObject(object, tagcounts)
3e170ce0 3599
5ba3f43e 3600 CountMapTags(kern.globals.kernel_map, tagcounts, slow)
3e170ce0
A
3601
3602 total = 0
cb323159 3603 totalmapped = 0
f427ee49 3604 tags = []
cb323159
A
3605 for tag in range(nsites):
3606 if all_tags or tagcounts[tag] or tagmapped[tag]:
f427ee49 3607 current = {}
3e170ce0 3608 total += tagcounts[tag]
cb323159
A
3609 totalmapped += tagmapped[tag]
3610 (sitestr, tagstr) = GetVMKernName(tag)
f427ee49
A
3611 current["name"] = sitestr
3612 current["size"] = tagcounts[tag]
3613 current["mapped"] = tagmapped[tag]
f427ee49
A
3614 current["tag"] = tag
3615 current["tagstr"] = tagstr
3616 current["subtotals"] = []
cb323159 3617
f427ee49 3618 site = kern.globals.vm_allocation_sites[tag]
cb323159
A
3619 for sub in range(site.subtotalscount):
3620 alloctag = unsigned(site.subtotals[sub].tag)
3621 amount = unsigned(site.subtotals[sub].total)
3622 subsite = kern.globals.vm_allocation_sites[alloctag]
3623 if alloctag and subsite:
cb323159 3624 (sitestr, tagstr) = GetVMKernName(alloctag)
f427ee49
A
3625 current["subtotals"].append({
3626 "amount": amount,
3627 "flags": int(subsite.flags),
3628 "tag": alloctag,
3629 "tagstr": tagstr,
3630 "sitestr": sitestr,
3631 })
3632 tags.append(current)
3633
c3c9b80d
A
3634 if "-O" in cmd_options:
3635 tags.sort(key = lambda tag: tag['size'])
3636
f427ee49
A
3637 if print_json:
3638 print json.dumps(tags)
3639 else:
3640 print " vm_allocation_tag_highest: {:<7d} ".format(nsites - 1)
c3c9b80d 3641 print " {:<7s} {:>7s} {:>7s} {:<50s}".format("tag.kmod", "size", "mapped", "name")
f427ee49
A
3642 for tag in tags:
3643 if not tagstr:
3644 tagstr = ""
c3c9b80d 3645 print " {:>3d}{:<4s} {:>7d}K {:>7d}K {:<50s}".format(tag["tag"], tag["tagstr"], tag["size"] / 1024, tag["mapped"] / 1024, tag["name"])
f427ee49
A
3646 for sub in tag["subtotals"]:
3647 if ((sub["flags"] & 0x007f) == 0):
3648 kind_str = "named"
3649 else:
3650 kind_str = "from"
cb323159 3651
c3c9b80d 3652 print " {:>7s} {:>7d}K {:s} {:>3d}{:<4s} {:<50s}".format(" ", sub["amount"] / 1024, kind_str, sub["tag"], sub["tagstr"], sub["sitestr"])
f427ee49 3653
c3c9b80d 3654 print "Total: {:>7d}K {:>7d}K".format(total / 1024, totalmapped / 1024)
3e170ce0
A
3655 return None
3656
3657
fe8ab488 3658def FindVMEntriesForVnode(task, vn):
5ba3f43e 3659 """ returns an array of vme that have the vnode set to defined vnode
fe8ab488
A
3660 each entry in array is of format (vme, start_addr, end_address, protection)
3661 """
3662 retval = []
3663 vmmap = task.map
3664 pmap = vmmap.pmap
3665 pager_ops_addr = unsigned(addressof(kern.globals.vnode_pager_ops))
3666 debuglog("pager_ops_addr %s" % hex(pager_ops_addr))
3667
3668 if unsigned(pmap) == 0:
3669 return retval
3670 vme_list_head = vmmap.hdr.links
3671 vme_ptr_type = gettype('vm_map_entry *')
3672 for vme in IterateQueue(vme_list_head, vme_ptr_type, 'links'):
3673 #print vme
3e170ce0
A
3674 if unsigned(vme.is_sub_map) == 0 and unsigned(vme.vme_object.vmo_object) != 0:
3675 obj = vme.vme_object.vmo_object
fe8ab488
A
3676 else:
3677 continue
3678
3679 while obj != 0:
3680 if obj.pager != 0:
3681 if obj.internal:
3682 pass
3683 else:
3684 vn_pager = Cast(obj.pager, 'vnode_pager *')
5ba3f43e 3685 if unsigned(vn_pager.vn_pgr_hdr.mo_pager_ops) == pager_ops_addr and unsigned(vn_pager.vnode_handle) == unsigned(vn):
fe8ab488
A
3686 retval.append((vme, unsigned(vme.links.start), unsigned(vme.links.end), unsigned(vme.protection)))
3687 obj = obj.shadow
3688 return retval
3689
3690@lldb_command('showtaskloadinfo')
3691def ShowTaskLoadInfo(cmd_args=None, cmd_options={}):
3692 """ Print the load address and uuid for the process
3693 Usage: (lldb)showtaskloadinfo <task_t>
3694 """
3695 if not cmd_args:
3696 raise ArgumentError("Insufficient arguments")
3697 t = kern.GetValueFromAddress(cmd_args[0], 'struct task *')
3698 print_format = "0x{0:x} - 0x{1:x} {2: <50s} (??? - ???) <{3: <36s}> {4: <50s}"
3699 p = Cast(t.bsd_info, 'struct proc *')
3700 uuid = p.p_uuid
3701 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)
3702 filepath = GetVnodePath(p.p_textvp)
3703 libname = filepath.split('/')[-1]
3704 #print "uuid: %s file: %s" % (uuid_out_string, filepath)
3705 mappings = FindVMEntriesForVnode(t, p.p_textvp)
3706 load_addr = 0
3707 end_addr = 0
3708 for m in mappings:
3709 if m[3] == 5:
3710 load_addr = m[1]
3711 end_addr = m[2]
3712 #print "Load address: %s" % hex(m[1])
3713 print print_format.format(load_addr, end_addr, libname, uuid_out_string, filepath)
3e170ce0
A
3714 return None
3715
3716@header("{0: <20s} {1: <20s} {2: <20s}".format("vm_page_t", "offset", "object"))
3717@lldb_command('vmpagelookup')
3718def VMPageLookup(cmd_args=None):
3719 """ Print the pages in the page bucket corresponding to the provided object and offset.
3720 Usage: (lldb)vmpagelookup <vm_object_t> <vm_offset_t>
3721 """
3722 if cmd_args == None or len(cmd_args) < 2:
3723 raise ArgumentError("Please specify an object and offset.")
3724 format_string = "{0: <#020x} {1: <#020x} {2: <#020x}\n"
3725
3726 obj = kern.GetValueFromAddress(cmd_args[0],'unsigned long long')
3727 off = kern.GetValueFromAddress(cmd_args[1],'unsigned long long')
3728
3729 hash_id = _calc_vm_page_hash(obj, off)
3730
3731 page_list = kern.globals.vm_page_buckets[hash_id].page_list
3732 print("hash_id: 0x%x page_list: 0x%x\n" % (unsigned(hash_id), unsigned(page_list)))
3733
3734 print VMPageLookup.header
3735 page = _vm_page_unpack_ptr(page_list)
3736 while (page != 0) :
3737 pg_t = kern.GetValueFromAddress(page, 'vm_page_t')
d9a64523
A
3738 print format_string.format(page, pg_t.vmp_offset, _vm_page_unpack_ptr(pg_t.vmp_object))
3739 page = _vm_page_unpack_ptr(pg_t.vmp_next_m)
3e170ce0 3740
39037602
A
3741
3742
3743@lldb_command('vmpage_get_phys_page')
3744def VmPageGetPhysPage(cmd_args=None):
3745 """ return the physical page for a vm_page_t
3746 usage: vm_page_get_phys_page <vm_page_t>
3747 """
3748 if cmd_args == None or len(cmd_args) < 1:
3749 print "Please provide valid vm_page_t. Type help vm_page_get_phys_page for help."
3750 return
3751
3752 page = kern.GetValueFromAddress(cmd_args[0], 'vm_page_t')
3753 phys_page = _vm_page_get_phys_page(page)
3754 print("phys_page = 0x%x\n" % phys_page)
3755
3756
3757def _vm_page_get_phys_page(page):
3758 if kern.arch == 'x86_64':
d9a64523 3759 return page.vmp_phys_page
39037602
A
3760
3761 if page == 0 :
3762 return 0
3763
3764 m = unsigned(page)
3765 if m >= unsigned(kern.globals.vm_page_array_beginning_addr) and m < unsigned(kern.globals.vm_page_array_ending_addr) :
3766 return (m - unsigned(kern.globals.vm_page_array_beginning_addr)) / sizeof('struct vm_page') + unsigned(kern.globals.vm_first_phys_ppnum)
3767
3768 page_with_ppnum = Cast(page, 'uint32_t *')
3769 ppnum_offset = sizeof('struct vm_page') / sizeof('uint32_t')
3770 return page_with_ppnum[ppnum_offset]
3771
3772
3773@lldb_command('vmpage_unpack_ptr')
3774def VmPageUnpackPtr(cmd_args=None):
3775 """ unpack a pointer
3776 usage: vm_page_unpack_ptr <packed_ptr>
3777 """
3778 if cmd_args == None or len(cmd_args) < 1:
3779 print "Please provide valid packed pointer argument. Type help vm_page_unpack_ptr for help."
3780 return
3781
3782 packed = kern.GetValueFromAddress(cmd_args[0],'unsigned long')
3783 unpacked = _vm_page_unpack_ptr(packed)
3784 print("unpacked pointer = 0x%x\n" % unpacked)
3785
3786
3e170ce0
A
3787def _vm_page_unpack_ptr(page):
3788 if kern.ptrsize == 4 :
3789 return page
3790
3791 if page == 0 :
3792 return page
3793
f427ee49
A
3794 params = kern.globals.vm_page_packing_params
3795 ptr_shift = params.vmpp_shift
39037602 3796 ptr_mask = kern.globals.vm_packed_from_vm_pages_array_mask
f427ee49
A
3797
3798 # when no mask and shift on 64bit systems, we're working with real/non-packed pointers
3799 if ptr_shift == 0 and ptr_mask == 0:
3800 return page
3801
3802 if unsigned(page) & unsigned(ptr_mask):
39037602 3803 masked_page = (unsigned(page) & ~ptr_mask)
0a7de745
A
3804 # can't use addressof(kern.globals.vm_pages[masked_page]) due to 32 bit limitation in SB bridge
3805 vm_pages_addr = unsigned(addressof(kern.globals.vm_pages[0]))
3806 element_size = unsigned(addressof(kern.globals.vm_pages[1])) - vm_pages_addr
3807 return (vm_pages_addr + masked_page * element_size)
2a1bd2d3 3808 return unsigned(vm_unpack_pointer(page, params))
3e170ce0
A
3809
3810@lldb_command('calcvmpagehash')
3811def CalcVMPageHash(cmd_args=None):
3812 """ Get the page bucket corresponding to the provided object and offset.
3813 Usage: (lldb)calcvmpagehash <vm_object_t> <vm_offset_t>
3814 """
3815 if cmd_args == None or len(cmd_args) < 2:
3816 raise ArgumentError("Please specify an object and offset.")
3817
3818 obj = kern.GetValueFromAddress(cmd_args[0],'unsigned long long')
3819 off = kern.GetValueFromAddress(cmd_args[1],'unsigned long long')
3820
3821 hash_id = _calc_vm_page_hash(obj, off)
3822
3823 print("hash_id: 0x%x page_list: 0x%x\n" % (unsigned(hash_id), unsigned(kern.globals.vm_page_buckets[hash_id].page_list)))
3824 return None
3825
3826def _calc_vm_page_hash(obj, off):
3827 bucket_hash = (int) (kern.globals.vm_page_bucket_hash)
3828 hash_mask = (int) (kern.globals.vm_page_hash_mask)
3829
3830 one = (obj * bucket_hash) & 0xFFFFFFFF
3831 two = off >> unsigned(kern.globals.page_shift)
3832 three = two ^ bucket_hash
3833 four = one + three
3834 hash_id = four & hash_mask
3835
3836 return hash_id
3837
cb323159
A
3838#Macro: showallocatedzoneelement
3839@lldb_command('showallocatedzoneelement')
3840def ShowAllocatedElementsInZone(cmd_args=None, cmd_options={}):
3841 """ Show all the allocated elements in a zone
3842 usage: showzoneallocelements <address of zone>
3843 """
3844 if len(cmd_args) < 1:
3845 raise ArgumentError("Please specify a zone")
3846
3847 zone = kern.GetValueFromAddress(cmd_args[0], 'struct zone *')
3848 elements = FindAllocatedElementsInZone(zone)
3849 i = 1
3850 for elem in elements:
3851 print "{0: >10d}/{1:<10d} element: {2: <#20x}".format(i, len(elements), elem)
3852 i += 1
3853
3854#EndMacro: showallocatedzoneelement
3855
3856def FindAllocatedElementsInZone(zone):
cb323159 3857 elements = []
cb323159 3858
c3c9b80d 3859 if not zone.z_self or zone.z_permanent:
f427ee49 3860 return elements
cb323159 3861
c3c9b80d 3862 for head in [zone.z_pageq_partial, zone.z_pageq_full]:
f427ee49 3863 for meta in ZoneIteratePageQueue(head):
f427ee49 3864 for elem in meta.iterateElements():
c3c9b80d 3865 if not meta.isElementFree(elem):
f427ee49 3866 elements.append(elem)
cb323159 3867
cb323159
A
3868 return elements
3869
3870def match_vm_page_attributes(page, matching_attributes):
3871 page_ptr = addressof(page)
3872 unpacked_vm_object = _vm_page_unpack_ptr(page.vmp_object)
3873 matched_attributes = 0
3874 if "vmp_q_state" in matching_attributes and (page.vmp_q_state == matching_attributes["vmp_q_state"]):
3875 matched_attributes += 1
3876 if "vm_object" in matching_attributes and (unsigned(unpacked_vm_object) == unsigned(matching_attributes["vm_object"])):
3877 matched_attributes += 1
3878 if "vmp_offset" in matching_attributes and (unsigned(page.vmp_offset) == unsigned(matching_attributes["vmp_offset"])):
3879 matched_attributes += 1
3880 if "phys_page" in matching_attributes and (unsigned(_vm_page_get_phys_page(page_ptr)) == unsigned(matching_attributes["phys_page"])):
3881 matched_attributes += 1
3882 if "bitfield" in matching_attributes and unsigned(page.__getattr__(matching_attributes["bitfield"])) == 1:
3883 matched_attributes += 1
3884
3885 return matched_attributes
3886
3887#Macro scan_vm_pages
3888@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"))
3889@lldb_command('scan_vm_pages', 'S:O:F:I:P:B:I:N:ZA')
3890def ScanVMPages(cmd_args=None, cmd_options={}):
3891 """ Scan the global vm_pages array (-A) and/or vmpages zone (-Z) for pages with matching attributes.
3892 usage: scan_vm_pages <matching attribute(s)> [-A start vm_pages index] [-N number of pages to scan] [-Z scan vm_pages zone]
3893
3894 scan_vm_pages -A: scan vm pages in the global vm_pages array
3895 scan_vm_pages -Z: scan vm pages allocated from the vm.pages zone
3896 scan_vm_pages <-A/-Z> -S <vm_page_q_state value>: Find vm pages in the specified queue
3897 scan_vm_pages <-A/-Z> -O <vm_object>: Find vm pages in the specified vm_object
3898 scan_vm_pages <-A/-Z> -F <offset>: Find vm pages with the specified vmp_offset value
3899 scan_vm_pages <-A/-Z> -P <phys_page>: Find vm pages with the specified physical page number
3900 scan_vm_pages <-A/-Z> -B <bitfield>: Find vm pages with the bitfield set
3901 scan_vm_pages <-A> -I <start_index>: Start the scan from start_index
3902 scan_vm_pages <-A> -N <npages>: Scan at most npages
3903 """
3904 if (len(cmd_options) < 1):
3905 raise ArgumentError("Please specify at least one matching attribute")
3906
3907 vm_pages = kern.globals.vm_pages
3908 vm_pages_count = kern.globals.vm_pages_count
3909
3910 start_index = 0
3911 npages = vm_pages_count
3912 scan_vmpages_array = False
3913 scan_vmpages_zone = False
3914 attribute_count = 0
3915
3916 if "-A" in cmd_options:
3917 scan_vmpages_array = True
3918
3919 if "-Z" in cmd_options:
3920 scan_vmpages_zone = True
3921
3922 if scan_vmpages_array == False and scan_vmpages_zone == False:
3923 raise ArgumentError("Please specify where to scan (-A: vm_pages array, -Z: vm.pages zone)")
3924
3925 attribute_values = {}
3926 if "-S" in cmd_options:
3927 attribute_values["vmp_q_state"] = kern.GetValueFromAddress(cmd_options["-S"], 'int')
3928 attribute_count += 1
3929
3930 if "-O" in cmd_options:
3931 attribute_values["vm_object"] = kern.GetValueFromAddress(cmd_options["-O"], 'vm_object_t')
3932 attribute_count += 1
3933
3934 if "-F" in cmd_options:
3935 attribute_values["vmp_offset"] = kern.GetValueFromAddress(cmd_options["-F"], 'unsigned long long')
3936 attribute_count += 1
3937
3938 if "-P" in cmd_options:
3939 attribute_values["phys_page"] = kern.GetValueFromAddress(cmd_options["-P"], 'unsigned int')
3940 attribute_count += 1
3941
3942 if "-B" in cmd_options:
3943 valid_vmp_bitfields = [
3944 "vmp_in_background",
3945 "vmp_on_backgroundq",
3946 "vmp_gobbled",
3947 "vmp_laundry",
3948 "vmp_no_cache",
3949 "vmp_private",
3950 "vmp_reference",
3951 "vmp_busy",
3952 "vmp_wanted",
3953 "vmp_tabled",
3954 "vmp_hashed",
3955 "vmp_fictitious",
3956 "vmp_clustered",
3957 "vmp_pmapped",
3958 "vmp_xpmapped",
3959 "vmp_free_when_done",
3960 "vmp_absent",
3961 "vmp_error",
3962 "vmp_dirty",
3963 "vmp_cleaning",
3964 "vmp_precious",
3965 "vmp_overwriting",
3966 "vmp_restart",
3967 "vmp_unusual",
3968 "vmp_cs_validated",
3969 "vmp_cs_tainted",
3970 "vmp_cs_nx",
3971 "vmp_reusable",
3972 "vmp_lopage",
3973 "vmp_written_by_kernel",
3974 "vmp_unused_object_bits"
3975 ]
3976 attribute_values["bitfield"] = cmd_options["-B"]
3977 if attribute_values["bitfield"] in valid_vmp_bitfields:
3978 attribute_count += 1
3979 else:
3980 raise ArgumentError("Unknown bitfield: {0:>20s}".format(bitfield))
3981
3982 if "-I" in cmd_options:
3983 start_index = kern.GetValueFromAddress(cmd_options["-I"], 'int')
3984 npages = vm_pages_count - start_index
3985
3986 if "-N" in cmd_options:
3987 npages = kern.GetValueFromAddress(cmd_options["-N"], 'int')
3988 if npages == 0:
3989 raise ArgumentError("You specified -N 0, nothing to be scanned")
3990
3991 end_index = start_index + npages - 1
3992 if end_index >= vm_pages_count:
3993 raise ArgumentError("Index range out of bound. vm_pages_count: {0:d}".format(vm_pages_count))
3994
3995 header_after_n_lines = 40
3996 format_string = "{0: >26s}{1: >#20x}{2: >10d}{3: >#20x}{4: >#20x}{5: >#16x}"
3997
3998 found_in_array = 0
3999 if scan_vmpages_array:
4000 print "Scanning vm_pages[{0:d} to {1:d}] for {2:d} matching attribute(s)......".format(start_index, end_index, attribute_count)
4001 i = start_index
4002 while i <= end_index:
4003 page = vm_pages[i]
4004 if match_vm_page_attributes(page, attribute_values) == attribute_count:
4005 if found_in_array % header_after_n_lines == 0:
4006 print ScanVMPages.header
4007
4008 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)))
4009 found_in_array += 1
4010
4011 i += 1
4012
4013 found_in_zone = 0
4014 if scan_vmpages_zone:
4015 page_size = kern.GetGlobalVariable('page_size')
4016 num_zones = kern.GetGlobalVariable('num_zones')
4017 zone_array = kern.GetGlobalVariable('zone_array')
4018 print "Scanning vm.pages zone for {0:d} matching attribute(s)......".format(attribute_count)
4019 i = 0
4020 while i < num_zones:
4021 zone = zone_array[i]
f427ee49 4022 if str(zone.z_name) == "vm pages":
cb323159
A
4023 break;
4024 i += 1
4025
4026 if i == num_zones:
4027 print "Cannot find vm_pages zone, skip the scan"
4028 else:
4029 print "Scanning page queues in the vm_pages zone..."
4030 elements = FindAllocatedElementsInZone(zone)
4031 for elem in elements:
4032 page = kern.GetValueFromAddress(elem, 'vm_page_t')
4033
4034 if match_vm_page_attributes(page, attribute_values) == attribute_count:
4035 if found_in_zone % header_after_n_lines == 0:
4036 print ScanVMPages.header
4037
4038 vm_object = _vm_page_unpack_ptr(page.vmp_object)
4039 phys_page = _vm_page_get_phys_page(page)
4040 print format_string.format("vm_pages zone", elem, page.vmp_q_state, vm_object, page.vmp_offset, phys_page)
4041 found_in_zone += 1
4042
4043 total = found_in_array + found_in_zone
4044 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)
4045
4046#EndMacro scan_vm_pages
4047
39037602
A
4048VM_PAGE_IS_WIRED = 1
4049
3e170ce0 4050@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"))
cb323159 4051@lldb_command('vmobjectwalkpages', 'CSBNQP:O:')
3e170ce0
A
4052def VMObjectWalkPages(cmd_args=None, cmd_options={}):
4053 """ Print the resident pages contained in the provided object. If a vm_page_t is provided as well, we
4054 specifically look for this page, highlighting it in the output or noting if it was not found. For
4055 each page, we confirm that it points to the object. We also keep track of the number of pages we
4056 see and compare this to the object's resident page count field.
4057 Usage:
4058 vmobjectwalkpages <vm_object_t> : Walk and print all the pages for a given object (up to 4K pages by default)
cb323159 4059 vmobjectwalkpages <vm_object_t> -C : list pages in compressor after processing resident pages
3e170ce0
A
4060 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
4061 vmobjectwalkpages <vm_object_t> -N : Walk and print all the pages for a given object, ignore the page limit
39037602 4062 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)
3e170ce0
A
4063 vmobjectwalkpages <vm_object_t> -P <vm_page_t> : Walk all the pages for a given object, annotate the specified page in the output with ***
4064 vmobjectwalkpages <vm_object_t> -P <vm_page_t> -S : Walk all the pages for a given object, stopping when we find the specified page
cb323159 4065 vmobjectwalkpages <vm_object_t> -O <offset> : Like -P, but looks for given offset
3e170ce0
A
4066
4067 """
4068
4069 if (cmd_args == None or len(cmd_args) < 1):
4070 raise ArgumentError("Please specify at minimum a vm_object_t and optionally a vm_page_t")
4071
4072 out_string = ""
4073
4074 obj = kern.GetValueFromAddress(cmd_args[0], 'vm_object_t')
4075
4076 page = 0
4077 if "-P" in cmd_options:
4078 page = kern.GetValueFromAddress(cmd_options['-P'], 'vm_page_t')
4079
cb323159
A
4080 off = -1
4081 if "-O" in cmd_options:
4082 off = kern.GetValueFromAddress(cmd_options['-O'], 'vm_offset_t')
4083
3e170ce0
A
4084 stop = 0
4085 if "-S" in cmd_options:
cb323159
A
4086 if page == 0 and off < 0:
4087 raise ArgumentError("-S can only be passed when a page is specified with -P or -O")
3e170ce0
A
4088 stop = 1
4089
4090 walk_backwards = False
4091 if "-B" in cmd_options:
4092 walk_backwards = True
4093
4094 quiet_mode = False
4095 if "-Q" in cmd_options:
4096 quiet_mode = True
4097
4098 if not quiet_mode:
4099 print VMObjectWalkPages.header
4100 format_string = "{0: <#10d} of {1: <#10d} {2: <#020x} {3: <#020x} {4: <#020x} {5: <#010x} {6: <#05d}\t"
39037602
A
4101 first_bitfield_format_string = "{0: <#2d}:{1: <#1d}:{2: <#1d}:{3: <#1d}:{4: <#1d}:{5: <#1d}:{6: <#1d}:{7: <#1d}\t"
4102 second_bitfield_format_string = "{0: <#1d}:{1: <#1d}:{2: <#1d}:{3: <#1d}:{4: <#1d}:{5: <#1d}:{6: <#1d}:"
4103 second_bitfield_format_string += "{7: <#1d}:{8: <#1d}:{9: <#1d}:{10: <#1d}:{11: <#1d}:{12: <#1d}:"
4104 second_bitfield_format_string += "{13: <#1d}:{14: <#1d}:{15: <#1d}:{16: <#1d}:{17: <#1d}:{18: <#1d}:{19: <#1d}:"
3e170ce0 4105 second_bitfield_format_string += "{20: <#1d}:{21: <#1d}:{22: <#1d}:{23: <#1d}:{24: <#1d}:{25: <#1d}:{26: <#1d}\n"
3e170ce0
A
4106
4107 limit = 4096 #arbitrary limit of number of pages to walk
4108 ignore_limit = 0
4109 if "-N" in cmd_options:
4110 ignore_limit = 1
4111
cb323159
A
4112 show_compressed = 0
4113 if "-C" in cmd_options:
4114 show_compressed = 1
4115
3e170ce0
A
4116 page_count = 0
4117 res_page_count = unsigned(obj.resident_page_count)
4118 page_found = False
4119 pages_seen = set()
4120
d9a64523 4121 for vmp in IterateQueue(obj.memq, "vm_page_t", "vmp_listq", walk_backwards, unpack_ptr_fn=_vm_page_unpack_ptr):
3e170ce0
A
4122 page_count += 1
4123 out_string = ""
4124 if (page != 0 and not(page_found) and vmp == page):
4125 out_string += "******"
4126 page_found = True
4127
cb323159
A
4128 if (off > 0 and not(page_found) and vmp.vmp_offset == off):
4129 out_string += "******"
4130 page_found = True
4131
4132 if page != 0 or off > 0 or quiet_mode:
3e170ce0
A
4133 if (page_count % 1000) == 0:
4134 print "traversed %d pages ...\n" % (page_count)
4135 else:
0a7de745 4136 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)
d9a64523
A
4137 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,
4138 vmp.vmp_private, vmp.vmp_reference)
3e170ce0 4139
d9a64523
A
4140 if hasattr(vmp,'slid'):
4141 vmp_slid = vmp.slid
4142 else:
4143 vmp_slid = 0
4144 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,
4145 vmp.vmp_pmapped, vmp.vmp_xpmapped, vmp.vmp_wpmapped, vmp.vmp_free_when_done, vmp.vmp_absent,
4146 vmp.vmp_error, vmp.vmp_dirty, vmp.vmp_cleaning, vmp.vmp_precious, vmp.vmp_overwriting,
4147 vmp.vmp_restart, vmp.vmp_unusual, 0, 0,
4148 vmp.vmp_cs_validated, vmp.vmp_cs_tainted, vmp.vmp_cs_nx, vmp.vmp_reusable, vmp.vmp_lopage, vmp_slid,
4149 vmp.vmp_written_by_kernel)
3e170ce0
A
4150
4151 if (vmp in pages_seen):
4152 print out_string + "cycle detected! we've seen vm_page_t: " + "{0: <#020x}".format(unsigned(vmp)) + " twice. stopping...\n"
4153 return
4154
d9a64523
A
4155 if (_vm_page_unpack_ptr(vmp.vmp_object) != unsigned(obj)):
4156 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)))
3e170ce0
A
4157 return
4158
d9a64523 4159 if (vmp.vmp_q_state == VM_PAGE_IS_WIRED) and (vmp.vmp_wire_count == 0):
39037602
A
4160 print out_string + " page in wired state with wire_count of 0\n"
4161 print "vm_page_t: " + "{0: <#020x}".format(unsigned(vmp)) + "\n"
3e170ce0
A
4162 print "stopping...\n"
4163 return
4164
f427ee49
A
4165 if (hasattr(vmp, 'vmp_unused_page_bits') and (vmp.vmp_unused_page_bits != 0)):
4166 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)
4167 print "stopping...\n"
4168 return
4169
4170 if (hasattr(vmp, 'vmp_unused_object_bits') and (vmp.vmp_unused_object_bits != 0)):
4171 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)
3e170ce0
A
4172 print "stopping...\n"
4173 return
4174
4175 pages_seen.add(vmp)
4176
4177 if False:
d9a64523 4178 hash_id = _calc_vm_page_hash(obj, vmp.vmp_offset)
3e170ce0
A
4179 hash_page_list = kern.globals.vm_page_buckets[hash_id].page_list
4180 hash_page = _vm_page_unpack_ptr(hash_page_list)
4181 hash_page_t = 0
4182
4183 while (hash_page != 0):
4184 hash_page_t = kern.GetValueFromAddress(hash_page, 'vm_page_t')
4185 if hash_page_t == vmp:
4186 break
d9a64523 4187 hash_page = _vm_page_unpack_ptr(hash_page_t.vmp_next_m)
3e170ce0
A
4188
4189 if (unsigned(vmp) != unsigned(hash_page_t)):
4190 print out_string + "unable to find page: " + "{0: <#020x}".format(unsigned(vmp)) + " from object in kernel page bucket list\n"
d9a64523 4191 print lldb_run_command("vm_page_info %s 0x%x" % (cmd_args[0], unsigned(vmp.vmp_offset)))
3e170ce0
A
4192 return
4193
4194 if (page_count >= limit and not(ignore_limit)):
4195 print out_string + "Limit reached (%d pages), stopping..." % (limit)
cb323159 4196 break
3e170ce0
A
4197
4198 print out_string
4199
4200 if page_found and stop:
4201 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)))
4202 return
4203
4204 if (page != 0):
4205 print("page found? : %s\n" % page_found)
4206
cb323159
A
4207 if (off > 0):
4208 print("page found? : %s\n" % page_found)
4209
3e170ce0
A
4210 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)))
4211
cb323159
A
4212 if show_compressed != 0 and obj.pager != 0 and unsigned(obj.pager.mo_pager_ops) == unsigned(addressof(kern.globals.compressor_pager_ops)):
4213 pager = Cast(obj.pager, 'compressor_pager *')
4214 chunks = pager.cpgr_num_slots / 128
4215 pagesize = kern.globals.page_size
4216
4217 page_idx = 0
4218 while page_idx < pager.cpgr_num_slots:
4219 if chunks != 0:
4220 chunk = pager.cpgr_slots.cpgr_islots[page_idx / 128]
4221 slot = chunk[page_idx % 128]
4222 elif pager.cpgr_num_slots > 2:
4223 slot = pager.cpgr_slots.cpgr_dslots[page_idx]
4224 else:
4225 slot = pager.cpgr_slots.cpgr_eslots[page_idx]
4226
4227 if slot != 0:
4228 print("compressed page for offset: %x slot %x\n" % ((page_idx * pagesize) - obj.paging_offset, slot))
4229 page_idx = page_idx + 1
4230
3e170ce0
A
4231
4232@lldb_command("show_all_apple_protect_pagers")
4233def ShowAllAppleProtectPagers(cmd_args=None):
4234 """Routine to print all apple_protect pagers
4235 usage: show_all_apple_protect_pagers
4236 """
c3c9b80d 4237 print "{:>3s} {:<3s} {:<18s} {:>5s} {:>5s} {:>6s} {:>6s} {:<18s} {:<18s} {:<18s} {:<18s} {:<18s}\n".format("#", "#", "pager", "refs", "ready", "mapped", "cached", "object", "offset", "crypto_offset", "crypto_start", "crypto_end")
3e170ce0
A
4238 qhead = kern.globals.apple_protect_pager_queue
4239 qtype = GetType('apple_protect_pager *')
4240 qcnt = kern.globals.apple_protect_pager_count
4241 idx = 0
4242 for pager in IterateQueue(qhead, qtype, "pager_queue"):
4243 idx = idx + 1
4244 show_apple_protect_pager(pager, qcnt, idx)
4245
4246@lldb_command("show_apple_protect_pager")
4247def ShowAppleProtectPager(cmd_args=None):
4248 """Routine to print out info about an apple_protect pager
4249 usage: show_apple_protect_pager <pager>
4250 """
4251 if cmd_args == None or len(cmd_args) < 1:
d9a64523 4252 print "Invalid argument.", ShowAppleProtectPager.__doc__
3e170ce0 4253 return
d9a64523 4254 pager = kern.GetValueFromAddress(cmd_args[0], 'apple_protect_pager_t')
3e170ce0
A
4255 show_apple_protect_pager(pager, 1, 1)
4256
4257def show_apple_protect_pager(pager, qcnt, idx):
4258 object = pager.backing_object
4259 shadow = object.shadow
4260 while shadow != 0:
4261 object = shadow
4262 shadow = object.shadow
4263 vnode_pager = Cast(object.pager,'vnode_pager *')
4264 filename = GetVnodePath(vnode_pager.vnode_handle)
c3c9b80d
A
4265 if hasattr(pager, "ap_pgr_hdr_ref"):
4266 refcnt = pager.ap_pgr_hdr_ref
4267 else:
4268 refcnt = pager.ap_pgr_hdr.mo_ref
4269 print "{:>3}/{:<3d} {: <#018x} {:>5d} {:>5d} {:>6d} {:>6d} {: <#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, refcnt, pager.is_ready, pager.is_mapped, pager.is_cached, 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)
4270 showvmobject(pager.backing_object, pager.backing_offset, pager.crypto_end - pager.crypto_start, 1, 1)
4271
4272@lldb_command("show_all_shared_region_pagers")
4273def ShowAllSharedRegionPagers(cmd_args=None):
4274 """Routine to print all shared_region pagers
4275 usage: show_all_shared_region_pagers
4276 """
4277 print "{:>3s} {:<3s} {:<18s} {:>5s} {:>5s} {:>6s} {:<18s} {:<18s} {:<18s} {:<18s}\n".format("#", "#", "pager", "refs", "ready", "mapped", "object", "offset", "jop_key", "slide", "slide_info")
4278 qhead = kern.globals.shared_region_pager_queue
4279 qtype = GetType('shared_region_pager *')
4280 qcnt = kern.globals.shared_region_pager_count
4281 idx = 0
4282 for pager in IterateQueue(qhead, qtype, "srp_queue"):
4283 idx = idx + 1
4284 show_shared_region_pager(pager, qcnt, idx)
4285
4286@lldb_command("show_shared_region_pager")
4287def ShowSharedRegionPager(cmd_args=None):
4288 """Routine to print out info about a shared_region pager
4289 usage: show_shared_region_pager <pager>
4290 """
4291 if cmd_args == None or len(cmd_args) < 1:
4292 print "Invalid argument.", ShowSharedRegionPager.__doc__
4293 return
4294 pager = kern.GetValueFromAddress(cmd_args[0], 'shared_region_pager_t')
4295 show_shared_region_pager(pager, 1, 1)
4296
4297def show_shared_region_pager(pager, qcnt, idx):
4298 object = pager.srp_backing_object
4299 shadow = object.shadow
4300 while shadow != 0:
4301 object = shadow
4302 shadow = object.shadow
4303 vnode_pager = Cast(object.pager,'vnode_pager *')
4304 filename = GetVnodePath(vnode_pager.vnode_handle)
4305 if hasattr(pager, 'srp_ref_count'):
4306 ref_count = pager.srp_ref_count
4307 else:
4308 ref_count = pager.srp_header.mo_ref
4309 if hasattr(pager, 'srp_jop_key'):
4310 jop_key = pager.srp_jop_key
4311 else:
4312 jop_key = -1
4313 print "{:>3}/{:<3d} {: <#018x} {:>5d} {:>5d} {:>6d} {: <#018x} {:#018x} {:#018x} {:#018x}\n\tvnode:{: <#018x} {:s}\n".format(idx, qcnt, pager, ref_count, pager.srp_is_ready, pager.srp_is_mapped, pager.srp_backing_object, pager.srp_backing_offset, jop_key, pager.srp_slide_info.si_slide, pager.srp_slide_info, vnode_pager.vnode_handle, filename)
4314 showvmobject(pager.srp_backing_object, pager.srp_backing_offset, pager.srp_slide_info.si_end - pager.srp_slide_info.si_start, 1, 1)
39037602
A
4315
4316@lldb_command("show_console_ring")
4317def ShowConsoleRingData(cmd_args=None):
4318 """ Print console ring buffer stats and data
4319 """
4320 cr = kern.globals.console_ring
4321 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)
4322 pending_data = []
4323 for i in range(unsigned(cr.used)):
4324 idx = ((unsigned(cr.read_ptr) - unsigned(cr.buffer)) + i) % unsigned(cr.len)
4325 pending_data.append("{:c}".format(cr.buffer[idx]))
4326
4327 if pending_data:
4328 print "Data:"
4329 print "".join(pending_data)
4330
4331# Macro: showjetsamsnapshot
4332
4333@lldb_command("showjetsamsnapshot", "DA")
4334def ShowJetsamSnapshot(cmd_args=None, cmd_options={}):
4335 """ Dump entries in the jetsam snapshot table
4336 usage: showjetsamsnapshot [-D] [-A]
4337 Use -D flag to print extra physfootprint details
4338 Use -A flag to print all entries (regardless of valid count)
4339 """
4340
4341 # Not shown are uuid, user_data, cpu_time
4342
4343 global kern
39037602
A
4344
4345 show_footprint_details = False
4346 show_all_entries = False
4347
4348 if "-D" in cmd_options:
4349 show_footprint_details = True
4350
4351 if "-A" in cmd_options:
4352 show_all_entries = True
4353
4354 valid_count = kern.globals.memorystatus_jetsam_snapshot_count
4355 max_count = kern.globals.memorystatus_jetsam_snapshot_max
4356
4357 if (show_all_entries == True):
4358 count = max_count
4359 else:
4360 count = valid_count
4361
4362 print "{:s}".format(valid_count)
4363 print "{:s}".format(max_count)
4364
4365 if int(count) == 0:
4366 print "The jetsam snapshot is empty."
4367 print "Use -A to force dump all entries (regardless of valid count)"
4368 return
4369
4370 # Dumps the snapshot header info
4371 print lldb_run_command('p *memorystatus_jetsam_snapshot')
4372
cb323159 4373 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}"
39037602 4374 if (show_footprint_details == True):
cb323159 4375 hdr_format += "{16: >15s} {17: >15s} {18: >12s} {19: >12s} {20: >17s} {21: >10s} {22: >13s} {23: >10s}"
39037602
A
4376
4377
4378 if (show_footprint_details == False):
cb323159
A
4379 print hdr_format.format('command', 'index', 'pri', 'cid', 'pid', 'starttime', 'killtime', 'idletime', 'kill', '#ents', 'fds', 'gen', 'state', 'footprint', 'purgeable', 'lifetimeMax')
4380 print hdr_format.format('', '', '', '', '', '(abs)', '(abs)', '(abs)', 'cause', '', '', 'Count', '', '(pages)', '(pages)', '(pages)')
39037602 4381 else:
cb323159
A
4382 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')
4383 print hdr_format.format('', '', '', '', '', '(abs)', '(abs)', '(abs)', 'cause', '', '', 'Count', '', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)', '(pages)')
39037602
A
4384
4385
4386 entry_format = "{e.name: >32s} {index: >5d} {e.priority: >4d} {e.jse_coalition_jetsam_id: >6d} {e.pid: >6d} "\
4387 "{e.jse_starttime: >20d} {e.jse_killtime: >20d} "\
4388 "{e.jse_idle_delta: >20d} {e.killed: >5d} {e.jse_memory_region_count: >10d} "\
cb323159 4389 "{e.fds: >6d} {e.jse_gencount: >6d} {e.state: >10x} {e.pages: >15d} "\
39037602
A
4390 "{e.purgeable_pages: >15d} {e.max_pages_lifetime: >15d}"
4391
4392 if (show_footprint_details == True):
4393 entry_format += "{e.jse_internal_pages: >15d} "\
4394 "{e.jse_internal_compressed_pages: >15d} "\
4395 "{e.jse_iokit_mapped_pages: >12d} "\
4396 "{e.jse_purgeable_nonvolatile_pages: >12d} "\
4397 "{e.jse_purgeable_nonvolatile_compressed_pages: >17d} "\
4398 "{e.jse_alternate_accounting_pages: >10d} "\
4399 "{e.jse_alternate_accounting_compressed_pages: >13d} "\
4400 "{e.jse_page_table_pages: >10d}"
4401
4402 snapshot_list = kern.globals.memorystatus_jetsam_snapshot.entries
4403 idx = 0
4404 while idx < count:
cb323159 4405 current_entry = dereference(Cast(addressof(snapshot_list[idx]), 'jetsam_snapshot_entry *'))
39037602
A
4406 print entry_format.format(index=idx, e=current_entry)
4407 idx +=1
4408 return
4409
4410# EndMacro: showjetsamsnapshot
813fb2f6
A
4411
4412# Macro: showvnodecleanblk/showvnodedirtyblk
4413
4414def _GetBufSummary(buf):
4415 """ Get a summary of important information out of a buf_t.
4416 """
4417 initial = "(struct buf) {0: <#0x} ="
4418
4419 # List all of the fields in this buf summary.
4420 entries = [buf.b_hash, buf.b_vnbufs, buf.b_freelist, buf.b_timestamp, buf.b_whichq,
4421 buf.b_flags, buf.b_lflags, buf.b_error, buf.b_bufsize, buf.b_bcount, buf.b_resid,
4422 buf.b_dev, buf.b_datap, buf.b_lblkno, buf.b_blkno, buf.b_iodone, buf.b_vp,
4423 buf.b_rcred, buf.b_wcred, buf.b_upl, buf.b_real_bp, buf.b_act, buf.b_drvdata,
4424 buf.b_fsprivate, buf.b_transaction, buf.b_dirtyoff, buf.b_dirtyend, buf.b_validoff,
4425 buf.b_validend, buf.b_redundancy_flags, buf.b_proc, buf.b_attr]
4426
4427 # Join an (already decent) string representation of each field
4428 # with newlines and indent the region.
4429 joined_strs = "\n".join([str(i).rstrip() for i in entries]).replace('\n', "\n ")
4430
4431 # Add the total string representation to our title and return it.
4432 out_str = initial.format(int(buf)) + " {\n " + joined_strs + "\n}\n\n"
4433 return out_str
4434
4435def _ShowVnodeBlocks(dirty=True, cmd_args=None):
4436 """ Display info about all [dirty|clean] blocks in a vnode.
4437 """
4438 if cmd_args == None or len(cmd_args) < 1:
4439 print "Please provide a valid vnode argument."
4440 return
4441
4442 vnodeval = kern.GetValueFromAddress(cmd_args[0], 'vnode *')
4443 list_head = vnodeval.v_cleanblkhd;
4444 if dirty:
4445 list_head = vnodeval.v_dirtyblkhd
4446
4447 print "Blocklist for vnode {}:".format(cmd_args[0])
4448
4449 i = 0
4450 for buf in IterateListEntry(list_head, 'struct buf *', 'b_hash'):
4451 # For each block (buf_t) in the appropriate list,
4452 # ask for a summary and print it.
4453 print "---->\nblock {}: ".format(i) + _GetBufSummary(buf)
4454 i += 1
4455 return
4456
4457@lldb_command('showvnodecleanblk')
4458def ShowVnodeCleanBlocks(cmd_args=None):
4459 """ Display info about all clean blocks in a vnode.
4460 usage: showvnodecleanblk <address of vnode>
4461 """
4462 _ShowVnodeBlocks(False, cmd_args)
4463
4464@lldb_command('showvnodedirtyblk')
4465def ShowVnodeDirtyBlocks(cmd_args=None):
4466 """ Display info about all dirty blocks in a vnode.
4467 usage: showvnodedirtyblk <address of vnode>
4468 """
4469 _ShowVnodeBlocks(True, cmd_args)
4470
4471# EndMacro: showvnodecleanblk/showvnodedirtyblk
d9a64523
A
4472
4473
4474@lldb_command("vm_page_lookup_in_map")
4475def VmPageLookupInMap(cmd_args=None):
4476 """Lookup up a page at a virtual address in a VM map
4477 usage: vm_page_lookup_in_map <map> <vaddr>
4478 """
4479 if cmd_args == None or len(cmd_args) < 2:
4480 print "Invalid argument.", VmPageLookupInMap.__doc__
4481 return
4482 map = kern.GetValueFromAddress(cmd_args[0], 'vm_map_t')
4483 vaddr = kern.GetValueFromAddress(cmd_args[1], 'vm_map_offset_t')
4484 print "vaddr {:#018x} in map {: <#018x}".format(vaddr, map)
4485 vm_page_lookup_in_map(map, vaddr)
4486
4487def vm_page_lookup_in_map(map, vaddr):
4488 vaddr = unsigned(vaddr)
4489 vme_list_head = map.hdr.links
4490 vme_ptr_type = GetType('vm_map_entry *')
4491 for vme in IterateQueue(vme_list_head, vme_ptr_type, "links"):
4492 if unsigned(vme.links.start) > vaddr:
4493 break
4494 if unsigned(vme.links.end) <= vaddr:
4495 continue
4496 offset_in_vme = vaddr - unsigned(vme.links.start)
4497 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)
4498 offset_in_object = offset_in_vme + (unsigned(vme.vme_offset) & ~0xFFF)
4499 if vme.is_sub_map:
4500 print "vaddr {:#018x} in map {: <#018x}".format(offset_in_object, vme.vme_object.vmo_submap)
4501 vm_page_lookup_in_map(vme.vme_object.vmo_submap, offset_in_object)
4502 else:
4503 vm_page_lookup_in_object(vme.vme_object.vmo_object, offset_in_object)
4504
4505@lldb_command("vm_page_lookup_in_object")
4506def VmPageLookupInObject(cmd_args=None):
4507 """Lookup up a page at a given offset in a VM object
4508 usage: vm_page_lookup_in_object <object> <offset>
4509 """
4510 if cmd_args == None or len(cmd_args) < 2:
4511 print "Invalid argument.", VmPageLookupInObject.__doc__
4512 return
4513 object = kern.GetValueFromAddress(cmd_args[0], 'vm_object_t')
4514 offset = kern.GetValueFromAddress(cmd_args[1], 'vm_object_offset_t')
4515 print "offset {:#018x} in object {: <#018x}".format(offset, object)
4516 vm_page_lookup_in_object(object, offset)
4517
4518def vm_page_lookup_in_object(object, offset):
4519 offset = unsigned(offset)
4520 page_size = kern.globals.page_size
4521 trunc_offset = offset & ~(page_size - 1)
4522 print " offset {:#018x} in VM object {: <#018x}".format(offset, object)
4523 hash_id = _calc_vm_page_hash(object, trunc_offset)
4524 page_list = kern.globals.vm_page_buckets[hash_id].page_list
4525 page = _vm_page_unpack_ptr(page_list)
4526 while page != 0:
4527 m = kern.GetValueFromAddress(page, 'vm_page_t')
4528 m_object_val = _vm_page_unpack_ptr(m.vmp_object)
4529 m_object = kern.GetValueFromAddress(m_object_val, 'vm_object_t')
4530 if unsigned(m_object) != unsigned(object) or unsigned(m.vmp_offset) != unsigned(trunc_offset):
4531 page = _vm_page_unpack_ptr(m.vmp_next_m)
4532 continue
4533 print " resident page {: <#018x} phys {:#010x}".format(m, _vm_page_get_phys_page(m))
4534 return
4535 if object.pager and object.pager_ready:
4536 offset_in_pager = trunc_offset + unsigned(object.paging_offset)
4537 if not object.internal:
4538 print " offset {:#018x} in external '{:s}' {: <#018x}".format(offset_in_pager, object.pager.mo_pager_ops.memory_object_pager_name, object.pager)
4539 return
4540 pager = Cast(object.pager, 'compressor_pager *')
4541 ret = vm_page_lookup_in_compressor_pager(pager, offset_in_pager)
4542 if ret:
4543 return
4544 if object.shadow and not object.phys_contiguous:
4545 offset_in_shadow = offset + unsigned(object.vo_un2.vou_shadow_offset)
4546 vm_page_lookup_in_object(object.shadow, offset_in_shadow)
4547 return
4548 print " page is absent and will be zero-filled on demand"
4549 return
4550
4551@lldb_command("vm_page_lookup_in_compressor_pager")
4552def VmPageLookupInCompressorPager(cmd_args=None):
4553 """Lookup up a page at a given offset in a compressor pager
4554 usage: vm_page_lookup_in_compressor_pager <pager> <offset>
4555 """
4556 if cmd_args == None or len(cmd_args) < 2:
4557 print "Invalid argument.", VmPageLookupInCompressorPager.__doc__
4558 return
4559 pager = kern.GetValueFromAddress(cmd_args[0], 'compressor_pager_t')
4560 offset = kern.GetValueFromAddress(cmd_args[1], 'memory_object_offset_t')
4561 print "offset {:#018x} in compressor pager {: <#018x}".format(offset, pager)
4562 vm_page_lookup_in_compressor_pager(pager, offset)
4563
4564def vm_page_lookup_in_compressor_pager(pager, offset):
4565 offset = unsigned(offset)
4566 page_size = unsigned(kern.globals.page_size)
4567 page_num = unsigned(offset / page_size)
4568 if page_num > pager.cpgr_num_slots:
4569 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)
4570 return 0
4571 slots_per_chunk = 512 / sizeof ('compressor_slot_t')
4572 num_chunks = unsigned((pager.cpgr_num_slots+slots_per_chunk-1) / slots_per_chunk)
4573 if num_chunks > 1:
4574 chunk_idx = unsigned(page_num / slots_per_chunk)
4575 chunk = pager.cpgr_slots.cpgr_islots[chunk_idx]
4576 slot_idx = unsigned(page_num % slots_per_chunk)
4577 slot = GetObjectAtIndexFromArray(chunk, slot_idx)
4578 slot_str = "islots[{:d}][{:d}]".format(chunk_idx, slot_idx)
4579 elif pager.cpgr_num_slots > 2:
4580 slot_idx = page_num
4581 slot = GetObjectAtIndexFromArray(pager.cpgr_slots.cpgr_dslots, slot_idx)
4582 slot_str = "dslots[{:d}]".format(slot_idx)
4583 else:
4584 slot_idx = page_num
4585 slot = GetObjectAtIndexFromArray(pager.cpgr_slots.cpgr_eslots, slot_idx)
4586 slot_str = "eslots[{:d}]".format(slot_idx)
4587 print " offset {:#018x} in compressor pager {: <#018x} {:s} slot {: <#018x}".format(offset, pager, slot_str, slot)
4588 if slot == 0:
4589 return 0
4590 slot_value = dereference(slot)
4591 print " value {:#010x}".format(slot_value)
4592 vm_page_lookup_in_compressor(Cast(slot, 'c_slot_mapping_t'))
4593 return 1
4594
4595@lldb_command("vm_page_lookup_in_compressor")
4596def VmPageLookupInCompressor(cmd_args=None):
4597 """Lookup up a page in a given compressor slot
4598 usage: vm_page_lookup_in_compressor <slot>
4599 """
4600 if cmd_args == None or len(cmd_args) < 1:
4601 print "Invalid argument.", VmPageLookupInCompressor.__doc__
4602 return
4603 slot = kern.GetValueFromAddress(cmd_args[0], 'compressor_slot_t *')
4604 print "compressor slot {: <#018x}".format(slot)
4605 vm_page_lookup_in_compressor(slot)
4606
4607C_SV_CSEG_ID = ((1 << 22) - 1)
4608
4609def vm_page_lookup_in_compressor(slot_ptr):
4610 slot_ptr = Cast(slot_ptr, 'compressor_slot_t *')
4611 slot_value = dereference(slot_ptr)
4612 slot = Cast(slot_value, 'c_slot_mapping')
4613 print slot
4614 print "compressor slot {: <#018x} -> {:#010x} cseg {:d} cindx {:d}".format(unsigned(slot_ptr), unsigned(slot_value), slot.s_cseg, slot.s_cindx)
4615 if slot_ptr == 0:
4616 return
4617 if slot.s_cseg == C_SV_CSEG_ID:
4618 sv = kern.globals.c_segment_sv_hash_table
4619 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)
4620 return
4621 if slot.s_cseg == 0 or unsigned(slot.s_cseg) > unsigned(kern.globals.c_segments_available):
4622 print "*** ERROR: s_cseg {:d} is out of bounds (1 - {:d})".format(slot.s_cseg, unsigned(kern.globals.c_segments_available))
4623 return
4624 c_segments = kern.globals.c_segments
4625 c_segments_elt = GetObjectAtIndexFromArray(c_segments, slot.s_cseg-1)
4626 c_seg = c_segments_elt.c_seg
4627 c_no_data = 0
4628 if hasattr(c_seg, 'c_state'):
4629 c_state = c_seg.c_state
4630 if c_state == 0:
4631 c_state_str = "C_IS_EMPTY"
4632 c_no_data = 1
4633 elif c_state == 1:
4634 c_state_str = "C_IS_FREE"
4635 c_no_data = 1
4636 elif c_state == 2:
4637 c_state_str = "C_IS_FILLING"
4638 elif c_state == 3:
4639 c_state_str = "C_ON_AGE_Q"
4640 elif c_state == 4:
4641 c_state_str = "C_ON_SWAPOUT_Q"
4642 elif c_state == 5:
4643 c_state_str = "C_ON_SWAPPEDOUT_Q"
4644 c_no_data = 1
4645 elif c_state == 6:
4646 c_state_str = "C_ON_SWAPPEDOUTSPARSE_Q"
4647 c_no_data = 1
4648 elif c_state == 7:
4649 c_state_str = "C_ON_SWAPPEDIN_Q"
4650 elif c_state == 8:
4651 c_state_str = "C_ON_MAJORCOMPACT_Q"
4652 elif c_state == 9:
4653 c_state_str = "C_ON_BAD_Q"
4654 c_no_data = 1
4655 else:
4656 c_state_str = "<unknown>"
4657 else:
4658 c_state = -1
4659 c_state_str = "<no c_state field>"
4660 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)
4661 c_indx = unsigned(slot.s_cindx)
4662 if hasattr(c_seg, 'c_slot_var_array'):
4663 c_seg_fixed_array_len = kern.globals.c_seg_fixed_array_len
4664 if c_indx < c_seg_fixed_array_len:
4665 cs = c_seg.c_slot_fixed_array[c_indx]
4666 else:
4667 cs = GetObjectAtIndexFromArray(c_seg.c_slot_var_array, c_indx - c_seg_fixed_array_len)
4668 else:
4669 C_SEG_SLOT_ARRAY_SIZE = 64
4670 C_SEG_SLOT_ARRAY_MASK = C_SEG_SLOT_ARRAY_SIZE - 1
4671 cs = GetObjectAtIndexFromArray(c_seg.c_slots[c_indx / C_SEG_SLOT_ARRAY_SIZE], c_indx & C_SEG_SLOT_ARRAY_MASK)
4672 print cs
f427ee49 4673 c_slot_unpacked_ptr = vm_unpack_ptr(cs.c_packed_ptr, kern.globals.c_slot_packing_params)
d9a64523
A
4674 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))
4675 if unsigned(slot_ptr) != unsigned(c_slot_unpacked_ptr):
4676 print "*** ERROR: compressor slot {: <#018x} points back to {: <#018x} instead of itself".format(slot_ptr, c_slot_unpacked_ptr)
4677 if c_no_data == 0:
4678 c_data = c_seg.c_store.c_buffer + (4 * cs.c_offset)
4679 c_size = cs.c_size
4680 cmd = "memory read {: <#018x} {: <#018x} --force".format(c_data, c_data + c_size)
4681 print cmd
4682 print lldb_run_command(cmd)
4683 else:
4684 print "<no compressed data>"
4685
d9a64523
A
4686@lldb_command('vm_scan_all_pages')
4687def VMScanAllPages(cmd_args=None):
4688 """Scans the vm_pages[] array
4689 """
4690 vm_pages_count = kern.globals.vm_pages_count
4691 vm_pages = kern.globals.vm_pages
4692
4693 free_count = 0
4694 local_free_count = 0
4695 active_count = 0
4696 local_active_count = 0
4697 inactive_count = 0
4698 speculative_count = 0
4699 throttled_count = 0
4700 wired_count = 0
4701 compressor_count = 0
4702 pageable_internal_count = 0
4703 pageable_external_count = 0
4704 secluded_count = 0
4705 secluded_free_count = 0
4706 secluded_inuse_count = 0
4707
4708 i = 0
4709 while i < vm_pages_count:
4710
4711 if i % 10000 == 0:
4712 print "{:d}/{:d}...\n".format(i,vm_pages_count)
4713
4714 m = vm_pages[i]
4715
4716 internal = 0
4717 external = 0
4718 m_object_val = _vm_page_unpack_ptr(m.vmp_object)
4719
4720 if m_object:
4721 if m_object.internal:
4722 internal = 1
4723 else:
4724 external = 1
4725
4726 if m.vmp_wire_count != 0 and m.vmp_local == 0:
4727 wired_count = wired_count + 1
4728 pageable = 0
4729 elif m.vmp_throttled:
4730 throttled_count = throttled_count + 1
4731 pageable = 0
4732 elif m.vmp_active:
4733 active_count = active_count + 1
4734 pageable = 1
4735 elif m.vmp_local:
4736 local_active_count = local_active_count + 1
4737 pageable = 0
4738 elif m.vmp_inactive:
4739 inactive_count = inactive_count + 1
4740 pageable = 1
4741 elif m.vmp_speculative:
4742 speculative_count = speculative_count + 1
4743 pageable = 0
4744 elif m.vmp_free:
4745 free_count = free_count + 1
4746 pageable = 0
4747 elif m.vmp_secluded:
4748 secluded_count = secluded_count + 1
4749 if m_object == 0:
4750 secluded_free_count = secluded_free_count + 1
4751 else:
4752 secluded_inuse_count = secluded_inuse_count + 1
4753 pageable = 0
4754 elif m_object == 0 and m.vmp_busy:
4755 local_free_count = local_free_count + 1
4756 pageable = 0
4757 elif m.vmp_compressor:
4758 compressor_count = compressor_count + 1
4759 pageable = 0
4760 else:
4761 print "weird page vm_pages[{:d}]?\n".format(i)
4762 pageable = 0
4763
4764 if pageable:
4765 if internal:
4766 pageable_internal_count = pageable_internal_count + 1
4767 else:
4768 pageable_external_count = pageable_external_count + 1
4769 i = i + 1
4770
4771 print "vm_pages_count = {:d}\n".format(vm_pages_count)
4772
4773 print "wired_count = {:d}\n".format(wired_count)
4774 print "throttled_count = {:d}\n".format(throttled_count)
4775 print "active_count = {:d}\n".format(active_count)
4776 print "local_active_count = {:d}\n".format(local_active_count)
4777 print "inactive_count = {:d}\n".format(inactive_count)
4778 print "speculative_count = {:d}\n".format(speculative_count)
4779 print "free_count = {:d}\n".format(free_count)
4780 print "local_free_count = {:d}\n".format(local_free_count)
4781 print "compressor_count = {:d}\n".format(compressor_count)
4782
4783 print "pageable_internal_count = {:d}\n".format(pageable_internal_count)
4784 print "pageable_external_count = {:d}\n".format(pageable_external_count)
4785 print "secluded_count = {:d}\n".format(secluded_count)
4786 print "secluded_free_count = {:d}\n".format(secluded_free_count)
4787 print "secluded_inuse_count = {:d}\n".format(secluded_inuse_count)
4788
4789
4790@lldb_command('show_all_vm_named_entries')
4791def ShowAllVMNamedEntries(cmd_args=None):
4792 """ Routine to print a summary listing of all the VM named entries
4793 """
4794 queue_len = kern.globals.vm_named_entry_count
4795 queue_head = kern.globals.vm_named_entry_list
4796
4797 print 'vm_named_entry_list:{: <#018x} vm_named_entry_count:{:d}\n'.format(kern.GetLoadAddressForSymbol('vm_named_entry_list'),queue_len)
4798
f427ee49 4799# 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")
d9a64523
A
4800 idx = 0
4801 for entry in IterateQueue(queue_head, 'struct vm_named_entry *', 'named_entry_list'):
4802 idx += 1
4803 showmemoryentry(entry, idx, queue_len)
4804
4805@lldb_command('show_vm_named_entry')
4806def ShowVMNamedEntry(cmd_args=None):
4807 """ Routine to print a VM named entry
4808 """
4809 if cmd_args == None or len(cmd_args) < 1:
4810 print "Invalid argument.", ShowMapVMNamedEntry.__doc__
4811 return
4812 named_entry = kern.GetValueFromAddress(cmd_args[0], 'vm_named_entry_t')
4813 showmemoryentry(named_entry, 0, 0)
4814
4815def showmemoryentry(entry, idx=0, queue_len=0):
4816 """ Routine to print out a summary a VM memory entry
4817 params:
4818 entry - core.value : a object of type 'struct vm_named_entry *'
4819 returns:
4820 None
4821 """
4822 show_pager_info = True
4823 show_all_shadows = True
4824
4825 backing = ""
4826 if entry.is_sub_map == 1:
4827 backing += "SUBMAP"
4828 if entry.is_copy == 1:
4829 backing += "COPY"
f427ee49 4830 if entry.is_object == 1:
d9a64523 4831 backing += "OBJECT"
f427ee49
A
4832 if entry.is_sub_map == 0 and entry.is_copy == 0 and entry.is_object == 0:
4833 backing += "***?***"
d9a64523
A
4834 prot=""
4835 if entry.protection & 0x1:
4836 prot += "r"
4837 else:
4838 prot += "-"
4839 if entry.protection & 0x2:
4840 prot += "w"
4841 else:
4842 prot += "-"
4843 if entry.protection & 0x4:
4844 prot += "x"
4845 else:
4846 prot += "-"
4847 extra_str = ""
4848 if hasattr(entry, 'named_entry_alias'):
4849 extra_str += " alias={:d}".format(entry.named_entry_alias)
4850 if hasattr(entry, 'named_entry_port'):
4851 extra_str += " port={:#016x}".format(entry.named_entry_port)
f427ee49 4852 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)
d9a64523
A
4853 if entry.is_sub_map == 1:
4854 showmapvme(entry.backing.map, 0, 0, show_pager_info, show_all_shadows)
f427ee49 4855 elif entry.is_copy == 1:
94ff46dc 4856 showmapcopyvme(entry.backing.copy, 0, 0, show_pager_info, show_all_shadows, 0)
f427ee49
A
4857 elif entry.is_object == 1:
4858 showmapcopyvme(entry.backing.copy, 0, 0, show_pager_info, show_all_shadows, 0)
4859 else:
4860 print "***** UNKNOWN TYPE *****"
4861 print " \n"
d9a64523
A
4862
4863
4864def IterateRBTreeEntry2(element, element_type, field_name1, field_name2):
4865 """ iterate over a rbtree as defined with RB_HEAD in libkern/tree.h
4866 element - value : Value object for rbh_root
4867 element_type - str : Type of the link element
4868 field_name - str : Name of the field in link element's structure
4869 returns:
4870 A generator does not return. It is used for iterating
4871 value : an object thats of type (element_type) head->sle_next. Always a pointer object
4872 """
4873 elt = element.__getattr__('rbh_root')
4874 if type(element_type) == str:
4875 element_type = gettype(element_type)
4876 charp_type = gettype('char *');
4877
4878 # Walk to find min
4879 parent = elt
4880 while unsigned(elt) != 0:
4881 parent = elt
4882 elt = cast(elt.__getattr__(field_name1).__getattr__(field_name2).__getattr__('rbe_left'), element_type)
4883 elt = parent
4884
4885 # Now elt is min
4886 while unsigned(elt) != 0:
4887 yield elt
4888 # implementation cribbed from RB_NEXT in libkern/tree.h
4889 right = cast(elt.__getattr__(field_name1).__getattr__(fieldname2).__getattr__('rbe_right'), element_type)
4890 if unsigned(right) != 0:
4891 elt = right
4892 left = cast(elt.__getattr__(field_name1).__getattr__(field_name2).__getattr__('rbe_left'), element_type)
4893 while unsigned(left) != 0:
4894 elt = left
4895 left = cast(elt.__getattr__(field_name1).__getattr(__field_name2).__getattr__('rbe_left'), element_type)
4896 else:
4897
4898 # avoid using GetValueFromAddress
4899 addr = elt.__getattr__(field_name1).__getattr__(field_name2).__getattr__('rbe_parent')&~1
4900 parent = value(elt.GetSBValue().CreateValueFromExpression(None,'(void *)'+str(addr)))
4901 parent = cast(parent, element_type)
4902
4903 if unsigned(parent) != 0:
4904 left = cast(parent.__getattr__(field_name1).__getattr__(field_name2).__getattr__('rbe_left'), element_type)
4905 if (unsigned(parent) != 0) and (unsigned(elt) == unsigned(left)):
4906 elt = parent
4907 else:
4908 if unsigned(parent) != 0:
4909 right = cast(parent.__getattr__(field_name1).__getattr__(field_name2).__getattr__('rbe_right'), element_type)
4910 while unsigned(parent) != 0 and (unsigned(elt) == unsigned(right)):
4911 elt = parent
4912
4913 # avoid using GetValueFromAddress
4914 addr = elt.__getattr__(field_name1).__getattr__(field_name2).__getattr__('rbe_parent')&~1
4915 parent = value(elt.GetSBValue().CreateValueFromExpression(None,'(void *)'+str(addr)))
4916 parent = cast(parent, element_type)
4917
4918 right = cast(parent.__getattr__(field_name1).__getattr__(field_name2).__getattr__('rbe_right'), element_type)
4919
4920 # avoid using GetValueFromAddress
4921 addr = elt.__getattr__(field_name1).__getattr__(field_name2).__getattr__('rbe_parent')&~1
4922 elt = value(elt.GetSBValue().CreateValueFromExpression(None,'(void *)'+str(addr)))
4923 elt = cast(elt, element_type)
4924
4925
4926@lldb_command("showmaprb")
4927def ShowMapRB(cmd_args=None):
4928 """Routine to print out a VM map's RB tree
4929 usage: showmaprb <vm_map>
4930 """
4931 if cmd_args == None or len(cmd_args) < 1:
4932 print "Invalid argument.", ShowMapRB.__doc__
4933 return
4934 map_val = kern.GetValueFromAddress(cmd_args[0], 'vm_map_t')
4935 print GetVMMapSummary.header
4936 print GetVMMapSummary(map_val)
4937 vme_rb_root = map_val.hdr.rb_head_store
4938 vme_ptr_type = GetType('struct vm_map_entry *')
4939 print GetVMEntrySummary.header
4940 for vme in IterateRBTreeEntry2(vme_rb_root, 'struct vm_map_entry *', 'store', 'entry'):
4941 print GetVMEntrySummary(vme)
4942 return None
4943
4944@lldb_command('show_all_owned_objects', 'T')
4945def ShowAllOwnedObjects(cmd_args=None, cmd_options={}):
4946 """ Routine to print the list of VM objects owned by each task
4947 -T: show only ledger-tagged objects
4948 """
4949 showonlytagged = False
4950 if "-T" in cmd_options:
4951 showonlytagged = True
4952 for task in kern.tasks:
4953 ShowTaskOwnedVmObjects(task, showonlytagged)
4954
4955@lldb_command('show_task_owned_objects', 'T')
4956def ShowTaskOwnedObjects(cmd_args=None, cmd_options={}):
4957 """ Routine to print the list of VM objects owned by the specified task
4958 -T: show only ledger-tagged objects
4959 """
4960 showonlytagged = False
4961 if "-T" in cmd_options:
4962 showonlytagged = True
4963 task = kern.GetValueFromAddress(cmd_args[0], 'task *')
4964 ShowTaskOwnedVmObjects(task, showonlytagged)
4965
f427ee49
A
4966@lldb_command('showdeviceinfo', 'J')
4967def ShowDeviceInfo(cmd_args=None, cmd_options={}):
4968 """ Routine to show basic device information (model, build, ncpus, etc...)
4969 Usage: memstats [-J]
4970 -J : Output json
4971 """
4972 print_json = False
4973 if "-J" in cmd_options:
4974 print_json = True
4975 device_info = {}
4976 device_info["build"] = str(kern.globals.osversion)
4977 device_info["memoryConfig"] = int(kern.globals.max_mem_actual)
4978 device_info["ncpu"] = int(kern.globals.ncpu)
4979 device_info["pagesize"] = int(kern.globals.page_size)
4980 device_info["mlockLimit"] = long(kern.globals.vm_global_user_wire_limit)
4981
4982
4983 if print_json:
4984 print json.dumps(device_info)
4985 else:
4986 PrettyPrintDictionary(device_info)
4987
d9a64523
A
4988def ShowTaskOwnedVmObjects(task, showonlytagged=False):
4989 """ Routine to print out a summary listing of all the entries in a vm_map
4990 params:
4991 task - core.value : a object of type 'task *'
4992 returns:
4993 None
4994 """
4995 taskobjq_total = lambda:None
4996 taskobjq_total.objects = 0
4997 taskobjq_total.vsize = 0
4998 taskobjq_total.rsize = 0
4999 taskobjq_total.wsize = 0
5000 taskobjq_total.csize = 0
5001 vmo_list_head = task.task_objq
5002 vmo_ptr_type = GetType('vm_object *')
5003 idx = 0
5004 for vmo in IterateQueue(vmo_list_head, vmo_ptr_type, "task_objq"):
5005 idx += 1
5006 if not showonlytagged or vmo.vo_ledger_tag != 0:
5007 if taskobjq_total.objects == 0:
5008 print ' \n'
5009 print GetTaskSummary.header + ' ' + GetProcSummary.header
5010 print GetTaskSummary(task) + ' ' + GetProcSummary(Cast(task.bsd_info, 'proc *'))
5011 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")
5012 ShowOwnedVmObject(vmo, idx, 0, taskobjq_total)
5013 if taskobjq_total.objects != 0:
5014 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)
5015 return None
5016
5017def ShowOwnedVmObject(object, idx, queue_len, taskobjq_total):
5018 """ Routine to print out a VM object owned by a task
5019 params:
5020 object - core.value : a object of type 'struct vm_object *'
5021 returns:
5022 None
5023 """
5024 page_size = kern.globals.page_size
5025 if object.purgable == 0:
5026 purgable = "N"
5027 elif object.purgable == 1:
5028 purgable = "V"
5029 elif object.purgable == 2:
5030 purgable = "E"
5031 elif object.purgable == 3:
5032 purgable = "D"
5033 else:
5034 purgable = "?"
5035 if object.pager == 0:
5036 compressed_count = 0
5037 else:
5038 compressor_pager = Cast(object.pager, 'compressor_pager *')
5039 compressed_count = compressor_pager.cpgr_num_slots_occupied
5040
5041 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))
5042
5043 taskobjq_total.objects += 1
5044 taskobjq_total.vsize += object.vo_un1.vou_size/page_size
5045 taskobjq_total.rsize += object.resident_page_count
5046 taskobjq_total.wsize += object.wired_page_count
5047 taskobjq_total.csize += compressed_count
5048
5049def GetProcPIDForObjectOwner(owner):
5050 """ same as GetProcPIDForTask() but deals with -1 for a disowned object
5051 """
5052 if unsigned(Cast(owner, 'int')) == unsigned(int(0xffffffff)):
5053 return -1
5054 return GetProcPIDForTask(owner)
5055
5056def GetProcNameForObjectOwner(owner):
5057 """ same as GetProcNameForTask() but deals with -1 for a disowned object
5058 """
5059 if unsigned(Cast(owner, 'int')) == unsigned(int(0xffffffff)):
5060 return "<disowned>"
5061 return GetProcNameForTask(owner)
5062
5063def GetDescForNamedEntry(mem_entry):
5064 out_str = "\n"
f427ee49 5065 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)
d9a64523
A
5066 if mem_entry.is_sub_map:
5067 out_str += " is_sub_map"
5068 elif mem_entry.is_copy:
5069 out_str += " is_copy"
f427ee49 5070 elif mem_entry.is_object:
d9a64523 5071 out_str += " is_object"
f427ee49
A
5072 else:
5073 out_str += " ???"
d9a64523 5074 return out_str