]> git.saurik.com Git - apple/xnu.git/blobdiff - tools/lldbmacros/ipc.py
xnu-4570.1.46.tar.gz
[apple/xnu.git] / tools / lldbmacros / ipc.py
old mode 100644 (file)
new mode 100755 (executable)
index d9c3745..9e5c482
@@ -8,6 +8,7 @@ from process import *
 from atm import *
 from bank import *
 from waitq import *
+from ioreg import *
 import xnudefines
 
 @header("{0: <20s} {1: <6s} {2: <6s} {3: <10s} {4: <15s}".format("task", "pid", '#acts', "tablesize", "command"))
@@ -249,6 +250,28 @@ def PrintPortSetMembers(space, setid, show_kmsg_summary):
         idx += 1
     return
 
+def FindEntryName(obj, space):
+    """ Routine to locate a port/ipc_object in an ipc_space
+        and return the name within that space.
+    """
+    if space == 0:
+        return 0
+
+    num_entries = int(space.is_table_size)
+    is_tableval = space.is_table
+    idx = 0
+    while idx < num_entries:
+        entry_val = GetObjectAtIndexFromArray(is_tableval, idx)
+        entry_bits= unsigned(entry_val.ie_bits)
+        entry_obj = 0
+        if (int(entry_bits) & 0x001f0000) != 0: ## it's a valid entry
+            entry_obj = unsigned(entry_val.ie_object)
+        if entry_obj == unsigned(obj):
+            nm = (idx << 8) | (entry_bits >> 24)
+            return nm
+        idx += 1
+    return 0
+
 
 @header("{0: <20s} {1: <28s} {2: <12s} {3: <6s} {4: <6s} {5: <20s} {6: <7s}\n".format(
             "portset", "waitqueue", "recvname", "flags", "refs", "recvname", "process"))
@@ -264,21 +287,22 @@ def PrintPortSetSummary(pset, space = 0):
     if config['verbosity'] > vHUMAN :
         show_kmsg_summary = True
 
+    local_name = FindEntryName(pset, space)
     setid = 0
     if pset.ips_object.io_bits & 0x80000000:
         setid = pset.ips_messages.data.pset.setq.wqset_id
         out_str += "{0: #019x}  {1: #019x} {2: <7s} {3: #011x}   {4: <4s} {5: >6d}  {6: #019x}   ".format(
                     unsigned(pset), addressof(pset.ips_messages), ' '*7,
-                    pset.ips_messages.data.pset.local_name, "ASet",
+                    local_name, "ASet",
                     pset.ips_object.io_references,
-                    pset.ips_messages.data.pset.local_name)
+                    local_name)
 
     else:
         out_str += "{0: #019x}  {1: #019x} {2: <7s} {3: #011x}   {4: <4s} {5: >6d}  {6: #019x}   ".format(
                     unsigned(pset), addressof(pset.ips_messages), ' '*7,
-                    pset.ips_messages.data.pset.local_name, "DSet",
+                    local_name, "DSet",
                     pset.ips_object.io_references,
-                    pset.ips_messages.data.pset.local_name)
+                    local_name)
     print out_str
 
     if setid != 0 and space != 0:
@@ -365,9 +389,18 @@ def GetKObjectFromPort(portval):
     io_bits = unsigned(portval.ip_object.io_bits)
     objtype_index = io_bits & 0xfff
     if objtype_index < len(xnudefines.kobject_types) :
-        desc_str = "kobject({0:s})".format(xnudefines.kobject_types[objtype_index])
-        if xnudefines.kobject_types[objtype_index] in ('TASK_RESUME', 'TASK'):
-            desc_str += " " + GetProcNameForTask(Cast(portval.kdata.kobject, 'task *'))
+        objtype_str = xnudefines.kobject_types[objtype_index]
+        if objtype_str == 'IOKIT_OBJ':
+            iokit_classnm = GetObjectTypeStr(portval.kdata.kobject)
+            if not iokit_classnm:
+                iokit_classnm = "<unknown class>"
+            else:
+                iokit_classnm = re.sub(r'vtable for ', r'', iokit_classnm)
+            desc_str = "kobject({:s}:{:s})".format(objtype_str, iokit_classnm)
+        else:
+            desc_str = "kobject({0:s})".format(objtype_str)
+            if xnudefines.kobject_types[objtype_index] in ('TASK_RESUME', 'TASK'):
+                desc_str += " " + GetProcNameForTask(Cast(portval.kdata.kobject, 'task *'))
     else:
         desc_str = "kobject(UNKNOWN) {:d}".format(objtype_index)
     return kobject_str + " " + desc_str
@@ -905,13 +938,17 @@ def GetIPCImportanceElemSummary(iie):
 
     out_str = ''
     fmt = "{: <#018x} {: <4s} {: <8d} {: <8d} {: <#018x} {: <#018x}"
-    type_str = 'TASK'
     if unsigned(iie.iie_bits) & 0x80000000:
         type_str = "INH"
+        inherit_count = 0
+    else:
+        type_str = 'TASK'
+        iit = Cast(iie, 'struct ipc_importance_task *')
+        inherit_count = sum(1 for i in IterateQueue(iit.iit_inherits, 'struct ipc_importance_inherit *',  'iii_inheritance'))
+
     refs = unsigned(iie.iie_bits) & 0x7fffffff
     made_refs = unsigned(iie.iie_made)
     kmsg_count = sum(1 for i in IterateQueue(iie.iie_kmsgs, 'struct ipc_kmsg *',  'ikm_inheritance'))
-    inherit_count = sum(1 for i in IterateQueue(iie.iie_inherits, 'struct ipc_importance_inherit *',  'iii_inheritance'))
     out_str += fmt.format(iie, type_str, refs, made_refs, kmsg_count, inherit_count)
     if config['verbosity'] > vHUMAN:
         if kmsg_count > 0:
@@ -921,7 +958,7 @@ def GetIPCImportanceElemSummary(iie):
             out_str += "\n"
         if inherit_count > 0:
             out_str += "\n\t" + GetIPCImportanceInheritSummary.header + "\n"
-            for i in IterateQueue(iie.iie_inherits, 'struct ipc_importance_inherit *',  'iii_inheritance'):
+            for i in IterateQueue(iit.iit_inherits, 'struct ipc_importance_inherit *',  'iii_inheritance'):
                 out_str += "\t" + GetIPCImportanceInheritSummary(i) + "\n"
             out_str += "\n"
         if type_str == "INH":
@@ -1090,6 +1127,8 @@ def GetBankHandleSummary(handle_ptr):
         params: handle_ptr - uint64 number stored in handle of voucher.
         returns: str - summary of bank element
     """
+    if handle_ptr == 1 :
+        return "Bank task of Current task"
     elem = kern.GetValueFromAddress(handle_ptr, 'bank_element_t')
     if elem.be_type & 1 :
         ba = Cast(elem, 'struct bank_account *')
@@ -1300,5 +1339,76 @@ def ShowVoucher(cmd_args=[], cmd_options={}):
     voucher = kern.GetValueFromAddress(cmd_args[0], 'ipc_voucher_t')
     print GetIPCVoucherSummary.header
     print GetIPCVoucherSummary(voucher, show_entries=True)
-    
 
+def GetSpaceSendRightEntries(space, port):
+    """ Get entry summaries for all send rights to port address in an IPC space.
+        params:
+            space - the IPC space to search for send rights
+            port_addr - the port address to match, or 0 to get all send rights
+        returns: an array of IPC entries
+    """
+    entry_table = space.is_table
+    ports = int(space.is_table_size)
+    i = 0
+    entries = []
+
+    while i < ports:
+        entry = GetObjectAtIndexFromArray(entry_table, i)
+
+        entry_ie_bits = unsigned(entry.ie_bits)
+        if (entry_ie_bits & 0x00010000) != 0 and (not port or entry.ie_object == port):
+            entries.append(entry)
+        i += 1
+
+    return entries
+
+@lldb_command('showportsendrights')
+def ShowPortSendRights(cmd_args=[], cmd_options={}):
+    """ Display a list of send rights across all tasks for a given port.
+        Usage: (lldb) showportsendrights <ipc_port_t>
+    """
+    if not cmd_args:
+        raise ArgumentError("no port address provided")
+    port = kern.GetValueFromAddress(cmd_args[0], 'struct ipc_port *')
+    i = 1
+
+    for t in kern.tasks:
+        # Write a progress line.  Using stderr avoids automatic newline when
+        # writing to stdout from lldb.  Blank spaces at the end clear out long
+        # lines.
+        sys.stderr.write("checking {:s} ({}/{})...{:30s}\r".format(Cast(t.bsd_info, 'proc_t').p_name, i, len(kern.tasks), ''))
+        i += 1
+        entries = GetSpaceSendRightEntries(t.itk_space, port)
+
+        if entries:
+            print GetTaskIPCSummary.header
+            print GetTaskIPCSummary(t)
+            print '\t' + GetIPCEntrySummary.header
+
+        for entry in entries:
+            print "\t" + GetIPCEntrySummary(entry)
+
+@lldb_command('showtasksuspenders')
+def ShowTaskSuspenders(cmd_args=[], cmd_options={}):
+    """ Display the tasks and send rights that are holding a target task suspended.
+        Usage: (lldb) showtasksuspenders <task_t>
+    """
+    if not cmd_args:
+        raise ArgumentError("no task address provided")
+    task = kern.GetValueFromAddress(cmd_args[0], 'task_t')
+
+    if task.suspend_count == 0:
+        print "task {:#x} ({:s}) is not suspended".format(unsigned(task), Cast(task.bsd_info, 'proc_t').p_name)
+        return
+
+    # If the task has been suspended by the kernel (potentially by
+    # kperf, using task_suspend_internal) or a client of task_suspend2
+    # that does not convert its task suspension token to a port using
+    # convert_task_suspension_token_to_port, then it's impossible to determine
+    # which task did the suspension.
+    port = task.itk_resume
+    if not port:
+        print "task {:#x} ({:s}) is suspended but no resume port exists".format(unsigned(task), Cast(task.bsd_info, 'proc_t').p_name)
+        return
+
+    return ShowPortSendRights(cmd_args=[unsigned(port)], cmd_options=cmd_options)