+@lldb_command('walkqueue_head', 'S')
+def WalkQueueHead(cmd_args=[], cmd_options={}):
+ """ walk a queue_head_t and list all members in it. Note this is for queue_head_t. refer to osfmk/kern/queue.h
+ Option: -S - suppress summary output.
+ Usage: (lldb) walkqueue_head <queue_entry *> <struct type> <fieldname>
+ ex: (lldb) walkqueue_head 0x7fffff80 "thread *" "task_threads"
+
+ """
+ global lldb_summary_definitions
+ if not cmd_args:
+ raise ArgumentError("invalid arguments")
+ if len(cmd_args) != 3:
+ raise ArgumentError("insufficient arguments")
+ queue_head = kern.GetValueFromAddress(cmd_args[0], 'struct queue_entry *')
+ el_type = cmd_args[1]
+ field_name = cmd_args[2]
+ showsummary = False
+ if el_type in lldb_summary_definitions:
+ showsummary = True
+ if '-S' in cmd_options:
+ showsummary = False
+
+ for i in IterateQueue(queue_head, el_type, field_name):
+ if showsummary:
+ print lldb_summary_definitions[el_type](i)
+ else:
+ print "{0: <#020x}".format(i)
+
+
+
+@lldb_command('walklist_entry', 'SE')
+def WalkList(cmd_args=[], cmd_options={}):
+ """ iterate over a list as defined with LIST_ENTRY in bsd/sys/queue.h
+ params:
+ object addr - value : address of object
+ element_type - str : Type of the next element
+ field_name - str : Name of the field in next element's structure
+
+ Options: -S - suppress summary output.
+ -E - Iterate using SLIST_ENTRYs
+
+ Usage: (lldb) walklist_entry <obj with list_entry *> <struct type> <fieldname>
+ ex: (lldb) walklist_entry 0x7fffff80 "struct proc *" "p_sibling"
+
+ """
+ global lldb_summary_definitions
+ if not cmd_args:
+ raise ArgumentError("invalid arguments")
+ if len(cmd_args) != 3:
+ raise ArgumentError("insufficient arguments")
+ el_type = cmd_args[1]
+ queue_head = kern.GetValueFromAddress(cmd_args[0], el_type)
+ field_name = cmd_args[2]
+ showsummary = False
+ if el_type in lldb_summary_definitions:
+ showsummary = True
+ if '-S' in cmd_options:
+ showsummary = False
+ if '-E' in cmd_options:
+ prefix = 's'
+ else:
+ prefix = ''
+ elt = queue_head
+ while unsigned(elt) != 0:
+ i = elt
+ elt = elt.__getattr__(field_name).__getattr__(prefix + 'le_next')
+ if showsummary:
+ print lldb_summary_definitions[el_type](i)
+ else:
+ print "{0: <#020x}".format(i)
+
+def trace_parse_Copt(Copt):
+ """Parses the -C option argument and returns a list of CPUs
+ """
+ cpusOpt = Copt
+ cpuList = cpusOpt.split(",")
+ chosen_cpus = []
+ for cpu_num_string in cpuList:
+ try:
+ if '-' in cpu_num_string:
+ parts = cpu_num_string.split('-')
+ if len(parts) != 2 or not (parts[0].isdigit() and parts[1].isdigit()):
+ raise ArgumentError("Invalid cpu specification: %s" % cpu_num_string)
+ firstRange = int(parts[0])
+ lastRange = int(parts[1])
+ if firstRange >= kern.globals.real_ncpus or lastRange >= kern.globals.real_ncpus:
+ raise ValueError()
+ if lastRange < firstRange:
+ raise ArgumentError("Invalid CPU range specified: `%s'" % cpu_num_string)
+ for cpu_num in range(firstRange, lastRange + 1):
+ if cpu_num not in chosen_cpus:
+ chosen_cpus.append(cpu_num)
+ else:
+ chosen_cpu = int(cpu_num_string)
+ if chosen_cpu < 0 or chosen_cpu >= kern.globals.real_ncpus:
+ raise ValueError()
+ if chosen_cpu not in chosen_cpus:
+ chosen_cpus.append(chosen_cpu)
+ except ValueError:
+ raise ArgumentError("Invalid CPU number specified. Valid range is 0..%d" % (kern.globals.real_ncpus - 1))
+
+ return chosen_cpus
+
+
+IDX_CPU = 0
+IDX_RINGPOS = 1
+IDX_RINGENTRY = 2
+def Trace_cmd(cmd_args=[], cmd_options={}, headerString=lambda:"", entryString=lambda x:"", ring=[], entries_per_cpu=0, max_backtraces=0):
+ """Generic trace dumper helper function
+ """
+
+ if '-S' in cmd_options:
+ field_arg = cmd_options['-S']
+ try:
+ getattr(ring[0][0], field_arg)
+ sort_key_field_name = field_arg
+ except AttributeError:
+ raise ArgumentError("Invalid sort key field name `%s'" % field_arg)
+ else:
+ sort_key_field_name = 'start_time_abs'
+
+ if '-C' in cmd_options:
+ chosen_cpus = trace_parse_Copt(cmd_options['-C'])
+ else:
+ chosen_cpus = [x for x in range(kern.globals.real_ncpus)]
+
+ try:
+ limit_output_count = int(cmd_options['-N'])
+ except ValueError:
+ raise ArgumentError("Invalid output count `%s'" % cmd_options['-N']);
+ except KeyError:
+ limit_output_count = None
+
+ reverse_sort = '-R' in cmd_options
+ backtraces = '-B' in cmd_options
+
+ # entries will be a list of 3-tuples, each holding the CPU on which the iotrace entry was collected,
+ # the original ring index, and the iotrace entry.
+ entries = []
+ for x in chosen_cpus:
+ ring_slice = [(x, y, ring[x][y]) for y in range(entries_per_cpu)]
+ entries.extend(ring_slice)
+
+ total_entries = len(entries)
+
+ entries.sort(key=lambda x: getattr(x[IDX_RINGENTRY], sort_key_field_name), reverse=reverse_sort)
+
+ if limit_output_count is not None and limit_output_count > total_entries:
+ print ("NOTE: Output count `%d' is too large; showing all %d entries" % (limit_output_count, total_entries));
+ limit_output_count = total_entries
+
+ if len(chosen_cpus) < kern.globals.real_ncpus:
+ print "NOTE: Limiting to entries from cpu%s %s" % ("s" if len(chosen_cpus) > 1 else "", str(chosen_cpus))
+
+ if limit_output_count is not None and limit_output_count < total_entries:
+ entries_to_display = limit_output_count
+ print "NOTE: Limiting to the %s" % ("first entry" if entries_to_display == 1 else ("first %d entries" % entries_to_display))
+ else:
+ entries_to_display = total_entries
+
+ print headerString()
+
+ for x in xrange(entries_to_display):
+ print entryString(entries[x])
+
+ if backtraces:
+ for btidx in range(max_backtraces):
+ nextbt = entries[x][IDX_RINGENTRY].backtrace[btidx]
+ if nextbt == 0:
+ break
+ print "\t" + GetSourceInformationForAddress(nextbt)
+
+
+@lldb_command('iotrace', 'C:N:S:RB')
+def IOTrace_cmd(cmd_args=[], cmd_options={}):
+ """ Prints the iotrace ring buffers for all CPUs by default.
+ Arguments:
+ -B : Print backtraces for each ring entry
+ -C <cpuSpec#>[,...,<cpuSpec#N>] : Limit trace entries to those generated by the specified CPUs (each cpuSpec can be a
+ single CPU number or a range separated by a dash (e.g. "0-3"))
+ -N <count> : Limit output to the first <count> entries (across all chosen CPUs)
+ -R : Display results in reverse-sorted order (oldest first; default is newest-first)
+ -S <sort_key_field_name> : Sort output by specified iotrace_entry_t field name (instead of by timestamp)
+ """
+ MAX_IOTRACE_BACKTRACES = 16
+
+ if kern.arch != "x86_64":
+ print "Sorry, iotrace is an x86-only command."
+ return
+
+ hdrString = lambda : "%-19s %-8s %-10s %-20s SZ %-18s %-17s DATA" % (
+ "START TIME",
+ "DURATION",
+ "CPU#[RIDX]",
+ " TYPE",
+ " VIRT ADDR",
+ " PHYS ADDR")
+
+ entryString = lambda x : "%-20u(%6u) %6s[%02d] %-20s %-2d 0x%016x 0x%016x 0x%x" % (
+ x[IDX_RINGENTRY].start_time_abs,
+ x[IDX_RINGENTRY].duration,
+ "CPU%d" % x[IDX_CPU],
+ x[IDX_RINGPOS],
+ str(x[IDX_RINGENTRY].iotype).split("=")[1].strip(),
+ x[IDX_RINGENTRY].size,
+ x[IDX_RINGENTRY].vaddr,
+ x[IDX_RINGENTRY].paddr,
+ x[IDX_RINGENTRY].val)
+
+ Trace_cmd(cmd_args, cmd_options, hdrString, entryString, kern.globals.iotrace_ring, kern.globals.iotrace_entries_per_cpu, MAX_IOTRACE_BACKTRACES)
+
+
+@lldb_command('ttrace', 'C:N:S:RB')
+def TrapTrace_cmd(cmd_args=[], cmd_options={}):
+ """ Prints the iotrace ring buffers for all CPUs by default.
+ Arguments:
+ -B : Print backtraces for each ring entry
+ -C <cpuSpec#>[,...,<cpuSpec#N>] : Limit trace entries to those generated by the specified CPUs (each cpuSpec can be a
+ single CPU number or a range separated by a dash (e.g. "0-3"))
+ -N <count> : Limit output to the first <count> entries (across all chosen CPUs)
+ -R : Display results in reverse-sorted order (oldest first; default is newest-first)
+ -S <sort_key_field_name> : Sort output by specified traptrace_entry_t field name (instead of by timestamp)
+ """
+ MAX_TRAPTRACE_BACKTRACES = 8
+
+ if kern.arch != "x86_64":
+ print "Sorry, ttrace is an x86-only command."
+ return
+
+ hdrString = lambda : "%-30s CPU#[RIDX] VECT INTERRUPTED_THREAD PREMLV INTRLV INTERRUPTED_PC" % (
+ "START TIME (DURATION [ns])")
+ entryString = lambda x : "%-20u(%6s) %8s[%02d] 0x%02x 0x%016x %6d %6d %s" % (
+ x[IDX_RINGENTRY].start_time_abs,
+ str(x[IDX_RINGENTRY].duration) if hex(x[IDX_RINGENTRY].duration) != "0xffffffffffffffff" else 'inprog',
+ "CPU%d" % x[IDX_CPU],
+ x[IDX_RINGPOS],
+ int(x[IDX_RINGENTRY].vector),
+ x[IDX_RINGENTRY].curthread,
+ x[IDX_RINGENTRY].curpl,
+ x[IDX_RINGENTRY].curil,
+ GetSourceInformationForAddress(x[IDX_RINGENTRY].interrupted_pc))
+
+ Trace_cmd(cmd_args, cmd_options, hdrString, entryString, kern.globals.traptrace_ring,
+ kern.globals.traptrace_entries_per_cpu, MAX_TRAPTRACE_BACKTRACES)
+
+
+@lldb_command('showsysctls', 'P:')
+def ShowSysctls(cmd_args=[], cmd_options={}):
+ """ Walks the list of sysctl data structures, printing out each during traversal.
+ Arguments:
+ -P <string> : Limit output to sysctls starting with the specified prefix.
+ """
+ if '-P' in cmd_options:
+ _ShowSysctl_prefix = cmd_options['-P']
+ allowed_prefixes = _ShowSysctl_prefix.split('.')
+ if allowed_prefixes:
+ for x in xrange(1, len(allowed_prefixes)):
+ allowed_prefixes[x] = allowed_prefixes[x - 1] + "." + allowed_prefixes[x]
+ else:
+ _ShowSysctl_prefix = ''
+ allowed_prefixes = []
+ def IterateSysctls(oid, parent_str, i):
+ headp = oid
+ parentstr = "<none>" if parent_str is None else parent_str
+ for pp in IterateListEntry(headp, 'struct sysctl_oid *', 'oid_link', 's'):
+ type = pp.oid_kind & 0xf
+ next_parent = str(pp.oid_name)
+ if parent_str is not None:
+ next_parent = parent_str + "." + next_parent
+ st = (" " * i) + str(pp.GetSBValue().Dereference()).replace("\n", "\n" + (" " * i))
+ if type == 1 and pp.oid_arg1 != 0:
+ # Check allowed_prefixes to see if we can recurse from root to the allowed prefix.
+ # To recurse further, we need to check only the the next parent starts with the user-specified
+ # prefix
+ if next_parent not in allowed_prefixes and next_parent.startswith(_ShowSysctl_prefix) is False:
+ continue
+ print 'parent = "%s"' % parentstr, st[st.find("{"):]
+ IterateSysctls(Cast(pp.oid_arg1, "struct sysctl_oid_list *"), next_parent, i + 2)
+ elif _ShowSysctl_prefix == '' or next_parent.startswith(_ShowSysctl_prefix):
+ print ('parent = "%s"' % parentstr), st[st.find("{"):]
+ IterateSysctls(kern.globals.sysctl__children, None, 0)
+
+
+