X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/3e170ce000f1506b7b5d2c5c7faec85ceabb573d..5ba3f43ea354af8ad55bea84372a2bc834d8757c:/tools/lldbmacros/ipc.py diff --git a/tools/lldbmacros/ipc.py b/tools/lldbmacros/ipc.py old mode 100644 new mode 100755 index d9c3745af..9e5c48215 --- a/tools/lldbmacros/ipc.py +++ b/tools/lldbmacros/ipc.py @@ -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 = "" + 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 + """ + 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 + """ + 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)