]> git.saurik.com Git - apple/xnu.git/blobdiff - tools/lldbmacros/xnu.py
xnu-7195.101.1.tar.gz
[apple/xnu.git] / tools / lldbmacros / xnu.py
index 7ec9ca7c8c88e76ae5419f73ea85f6b72848dbb9..ce5997b5efed37be4e52d43dfa59383821eebf6d 100755 (executable)
@@ -284,7 +284,7 @@ def GetObjectAtIndexFromArray(array_base, index):
     base_address = array_base_val.GetValueAsUnsigned()
     size = array_base_val.GetType().GetPointeeType().GetByteSize()
     obj_address = base_address + (index * size)
-    obj = kern.GetValueFromAddress(obj_address, array_base_val.GetType().GetName())
+    obj = kern.GetValueFromAddress(obj_address, array_base_val.GetType())
     return Cast(obj, array_base_val.GetType())
 
 
@@ -669,8 +669,15 @@ def ParseMacOSPanicLog(panic_header, cmd_options={}):
     if other_log_begin_offset != 0 and (other_log_len == 0 or other_log_len < (cur_debug_buf_ptr_offset - other_log_begin_offset)):
         other_log_len = cur_debug_buf_ptr_offset - other_log_begin_offset
     expected_panic_magic = xnudefines.MACOS_PANIC_MAGIC
-    panic_stackshot_addr = unsigned(panic_header) + unsigned(panic_header.mph_stackshot_offset)
-    panic_stackshot_len = unsigned(panic_header.mph_stackshot_len)
+
+    # use the global if it's available (on an x86 corefile), otherwise refer to the header
+    if hasattr(kern.globals, "panic_stackshot_buf"):
+        panic_stackshot_addr = unsigned(kern.globals.panic_stackshot_buf)
+        panic_stackshot_len = unsigned(kern.globals.panic_stackshot_len)
+    else:
+        panic_stackshot_addr = unsigned(panic_header) + unsigned(panic_header.mph_stackshot_offset)
+        panic_stackshot_len = unsigned(panic_header.mph_stackshot_len)
+
     panic_header_flags = unsigned(panic_header.mph_panic_flags)
 
     warn_str = ""
@@ -756,7 +763,7 @@ def ParseAURRPanicLog(panic_header, cmd_options={}):
 
         # Adjust panic log string length (cap to maximum supported values)
         if panic_log_version == xnudefines.AURR_PANIC_VERSION:
-            max_string_len = panic_log_reset_log_len and min(panic_log_reset_log_len, xnudefines.AURR_PANIC_STRING_LEN) or 0
+            max_string_len = panic_log_reset_log_len
         elif panic_log_version == xnudefines.AURR_CRASHLOG_PANIC_VERSION:
             max_string_len = xnudefines.CRASHLOG_PANIC_STRING_LEN
 
@@ -948,7 +955,7 @@ def WalkQueueHead(cmd_args=[], cmd_options={}):
 
 
 
-@lldb_command('walklist_entry', 'S')
+@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:
@@ -956,7 +963,9 @@ def WalkList(cmd_args=[], cmd_options={}):
             element_type - str   : Type of the next element
             field_name   - str   : Name of the field in next element's structure
 
-        Option: -S - suppress summary output.
+        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"
 
@@ -969,22 +978,25 @@ def WalkList(cmd_args=[], cmd_options={}):
     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).le_next
+        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 iotrace_parse_Copt(Copt):
+def trace_parse_Copt(Copt):
     """Parses the -C option argument and returns a list of CPUs
     """
     cpusOpt = Copt
@@ -1017,30 +1029,17 @@ def iotrace_parse_Copt(Copt):
     return chosen_cpus
 
 
-@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)
+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
     """
-    IDX_CPU = 0
-    IDX_RINGPOS = 1
-    IDX_RINGENTRY = 2
-    MAX_IOTRACE_BACKTRACES = 16
-
-    if kern.arch != "x86_64":
-        print "Sorry, iotrace is an x86-only command."
-        return
 
     if '-S' in cmd_options:
         field_arg = cmd_options['-S']
         try:
-            getattr(kern.globals.iotrace_ring[0][0], field_arg)
+            getattr(ring[0][0], field_arg)
             sort_key_field_name = field_arg
         except AttributeError:
             raise ArgumentError("Invalid sort key field name `%s'" % field_arg)
@@ -1048,7 +1047,7 @@ def IOTrace_cmd(cmd_args=[], cmd_options={}):
             sort_key_field_name = 'start_time_abs'
 
     if '-C' in cmd_options:
-        chosen_cpus = iotrace_parse_Copt(cmd_options['-C'])
+        chosen_cpus = trace_parse_Copt(cmd_options['-C'])
     else:
         chosen_cpus = [x for x in range(kern.globals.real_ncpus)]
 
@@ -1066,7 +1065,7 @@ def IOTrace_cmd(cmd_args=[], cmd_options={}):
     # the original ring index, and the iotrace entry. 
     entries = []
     for x in chosen_cpus:
-        ring_slice = [(x, y, kern.globals.iotrace_ring[x][y]) for y in range(kern.globals.iotrace_entries_per_cpu)]
+        ring_slice = [(x, y, ring[x][y]) for y in range(entries_per_cpu)]
         entries.extend(ring_slice)
 
     total_entries = len(entries)
@@ -1086,34 +1085,192 @@ def IOTrace_cmd(cmd_args=[], cmd_options={}):
     else:
         entries_to_display = total_entries
 
-    print "%-19s %-8s %-10s %-20s SZ %-18s %-17s DATA" % (
-        "START TIME",
-        "DURATION",
-        "CPU#[RIDX]",
-        "      TYPE",
-        "   VIRT ADDR",
-        "   PHYS ADDR")
+    print headerString()
 
     for x in xrange(entries_to_display):
-        print "%-20u(%6u) %6s[%02d] %-20s %d 0x%016x 0x%016x 0x%x" % (
-            entries[x][IDX_RINGENTRY].start_time_abs,
-            entries[x][IDX_RINGENTRY].duration,
-            "CPU%d" % entries[x][IDX_CPU],
-            entries[x][IDX_RINGPOS],
-            str(entries[x][IDX_RINGENTRY].iotype).split("=")[1].strip(),
-            entries[x][IDX_RINGENTRY].size,
-            entries[x][IDX_RINGENTRY].vaddr,
-            entries[x][IDX_RINGENTRY].paddr,
-            entries[x][IDX_RINGENTRY].val)
+        print entryString(entries[x])
+
         if backtraces:
-            for btidx in range(MAX_IOTRACE_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)
+
+# Yields an iterator over all the sysctls from the provided root.
+# Can optionally filter by the given prefix
+def IterateSysctls(root_oid=kern.globals.sysctl__children, prefix="", depth = 0, parent = ""):
+    headp = root_oid
+    for pp in IterateListEntry(headp, 'struct sysctl_oid *', 'oid_link', 's'):
+        node_str = ""
+        if prefix != "":
+            node_str = str(pp.oid_name)
+            if parent != "":
+                node_str = parent + "." + node_str
+                if node_str.startswith(prefix):
+                    yield pp, depth, parent
+        else:
+            yield pp, depth, parent
+        type = pp.oid_kind & 0xf
+        if type == 1 and pp.oid_arg1 != 0:
+            if node_str == "":
+                next_parent = str(pp.oid_name)
+                if parent != "":
+                    next_parent = parent + "." + next_parent
+            else:
+                next_parent = node_str
+            # Only recurse if the next parent starts with our allowed prefix.
+            # Note that it's OK if the parent string is too short (because the prefix might be for a deeper node).
+            prefix_len = min(len(prefix), len(next_parent))
+            if next_parent[:prefix_len] == prefix[:prefix_len]:
+                for x in IterateSysctls(Cast(pp.oid_arg1, "struct sysctl_oid_list *"), prefix, depth + 1, next_parent):
+                    yield x
+
+@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 = []
+
+    for sysctl, depth, parentstr in IterateSysctls(kern.globals.sysctl__children, _ShowSysctl_prefix):
+        if parentstr == "":
+            parentstr = "<none>"
+        headp = sysctl
+        st = (" " * depth * 2) + str(sysctl.GetSBValue().Dereference()).replace("\n", "\n" + (" " * depth * 2))
+        print 'parent = "%s"' % parentstr, st[st.find("{"):]
+
+@lldb_command('showexperiments', 'F')
+def ShowExperiments(cmd_args=[], cmd_options={}):
+    """ Shows any active kernel experiments being run on the device via trial.
+        Arguments:
+        -F: Scan for changed experiment values even if no trial identifiers have been set.
+    """
+
+    treatment_id = str(kern.globals.trial_treatment_id)
+    experiment_id = str(kern.globals.trial_experiment_id)
+    deployment_id = kern.globals.trial_deployment_id._GetValueAsSigned()
+    if treatment_id == "" and experiment_id == "" and deployment_id == -1:
+        print("Device is not enrolled in any kernel experiments.")
+        if not '-F' in cmd_options:
+            return
+    else:
+        print("""Device is enrolled in a kernel experiment:
+    treatment_id: %s
+    experiment_id: %s
+    deployment_id: %d""" % (treatment_id, experiment_id, deployment_id))
+
+    print("Scanning sysctl tree for modified factors...")
+
+    kExperimentFactorFlag = 0x00100000
+    
+    formats = {
+            "IU": gettype("unsigned int *"),
+            "I": gettype("int *"),
+            "LU": gettype("unsigned long *"),
+            "L": gettype("long *"),
+            "QU": gettype("uint64_t *"),
+            "Q": gettype("int64_t *")
+    }
+
+    for sysctl, depth, parentstr in IterateSysctls(kern.globals.sysctl__children):
+        if sysctl.oid_kind & kExperimentFactorFlag:
+            spec = cast(sysctl.oid_arg1, "struct experiment_spec *")
+            # Skip if arg2 isn't set to 1 (indicates an experiment factor created without an experiment_spec).
+            if sysctl.oid_arg2 == 1:
+                if spec.modified == 1:
+                    fmt = str(sysctl.oid_fmt)
+                    ptr = spec.ptr
+                    t = formats.get(fmt, None)
+                    if t:
+                        value = cast(ptr, t)
+                    else:
+                        # Unknown type
+                        continue
+                    name = str(parentstr) + "." + str(sysctl.oid_name)
+                    print("%s = %d (Default value is %d)" % (name, dereference(value), spec.original_value))
 
 from memory import *
 from process import *
@@ -1129,7 +1286,6 @@ from pci import *
 from misc import *
 from apic import *
 from scheduler import *
-from atm import *
 from structanalyze import *
 from ipcimportancedetail import *
 from bank import *
@@ -1147,3 +1303,4 @@ from ulock import *
 from ntstat import *
 from zonetriage import *
 from sysreg import *
+from counter import *