X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/39236c6e673c41db228275375ab7fdb0f837b292..4bd07ac2140668789aa3ee8ec4dde4a3e0a3bba5:/tools/lldbmacros/process.py diff --git a/tools/lldbmacros/process.py b/tools/lldbmacros/process.py index 11f9ef452..e2ddb8e3d 100644 --- a/tools/lldbmacros/process.py +++ b/tools/lldbmacros/process.py @@ -1,14 +1,43 @@ """ Please make sure you read the README file COMPLETELY BEFORE reading anything below. - It is very critical that you read coding guidelines in Section E in README file. + It is very critical that you read coding guidelines in Section E in README file. """ from xnu import * import sys, shlex from utils import * from core.lazytarget import * +import time import xnudefines +def GetProcNameForTask(task): + """ returns a string name of the process. if proc is not valid "unknown" is returned + params: + task: value object represeting a task in the kernel. + returns: + str : A string name of the process linked to the task + """ + if not task or not unsigned(task.bsd_info): + return "unknown" + p = Cast(task.bsd_info, 'proc *') + return str(p.p_comm) + +def GetProcPIDForTask(task): + """ returns a int pid of the process. if the proc is not valid, val[5] from audit_token is returned. + params: + task: value object representing a task in the kernel + returns: + int : pid of the process or -1 if not found + """ + if task and unsigned(task.bsd_info): + p = Cast(task.bsd_info, 'proc *') + return unsigned(p.p_pid) + + if task : + return unsigned(task.audit_token.val[5]) + + return -1 + def GetProcInfo(proc): """ returns a string name, pid, parent and task for a proc_t. Decodes cred, flag and p_stat fields. params: @@ -92,22 +121,91 @@ def ZombProc(cmd_args=None): params: cmd_args - [] : array of strings passed from lldb command prompt """ - for proc in kern.zombprocs: - print GetProcInfo(proc) + if len(kern.zombprocs) != 0: + print "\nZombie Processes:" + for proc in kern.zombprocs: + print GetProcInfo(proc) + "\n\n" + +@lldb_command('zombtasks') +def ZombTasks(cmd_args=None): + """ Routine to print out all tasks in the zombie list + params: None + """ + out_str = "" + if len(kern.zombprocs) != 0: + header = "\nZombie Tasks:\n" + header += GetTaskSummary.header + " " + GetProcSummary.header + for proc in kern.zombprocs: + if proc.p_stat != 5: + t = Cast(proc.task, 'task *') + out_str += GetTaskSummary(t) +" "+ GetProcSummary(proc) + "\n" + if out_str != "": + print header + print out_str @lldb_command('zombstacks') def ZombStacks(cmd_args=None): """ Routine to print out all stacks of tasks that are exiting """ + header_flag = 0 for proc in kern.zombprocs: if proc.p_stat != 5: + if header_flag == 0: + print "\nZombie Stacks:" + header_flag = 1 t = Cast(proc.task, 'task *') ShowTaskStacks(t) #End of Zombstacks +def GetASTSummary(ast): + """ Summarizes an AST field + Flags: + P - AST_PREEMPT + Q - AST_QUANTUM + U - AST_URGENT + H - AST_HANDOFF + Y - AST_YIELD + A - AST_APC + L - AST_LEDGER + B - AST_BSD + K - AST_KPERF + M - AST_MACF + C - AST_CHUD + C - AST_CHUD_URGENT + G - AST_GUARD + T - AST_TELEMETRY_USER + T - AST_TELEMETRY_KERNEL + T - AST_TELEMETRY_WINDOWED + S - AST_SFI + """ + out_string = "" + state = int(ast) + thread_state_chars = {0x0:'', 0x1:'P', 0x2:'Q', 0x4:'U', 0x8:'H', 0x10:'Y', 0x20:'A', + 0x40:'L', 0x80:'B', 0x100:'K', 0x200:'M', 0x400:'C', 0x800:'C', + 0x1000:'G', 0x2000:'T', 0x4000:'T', 0x8000:'T', 0x10000:'S'} + state_str = '' + mask = 0x1 + while mask <= 0x10000: + state_str += thread_state_chars[int(state & mask)] + mask = mask << 1 + + return state_str + + +@lldb_type_summary(['kcdata_descriptor *', 'kcdata_descriptor_t']) +@header("{0: <20s} {1: <20s} {2: <20s} {3: <10s} {4: <5s}".format("kcdata_descriptor", "begin_addr", "cur_pos", "size", "flags")) +def GetKCDataSummary(kcdata): + """ Summarizes kcdata_descriptor structure + params: kcdata: value - value object representing kcdata_descriptor + returns: str - summary of the kcdata object + """ + format_string = "{0: <#020x} {1: <#020x} {2: <#020x} {3: <10d} {4: <#05x}" + return format_string.format(kcdata, kcdata.kcd_addr_begin, kcdata.kcd_addr_end, kcdata.kcd_length, kcdata.kcd_flags) + + @lldb_type_summary(['task', 'task_t']) @header("{0: <20s} {1: <20s} {2: <20s} {3: >5s} {4: <5s}".format("task","vm_map", "ipc_space", "#acts", "flags")) -def GetTaskSummary(task): +def GetTaskSummary(task, showcorpse=False): """ Summarizes the important fields in task structure. params: task: value - value object representing a task in kernel returns: str - summary of the task @@ -120,31 +218,75 @@ def GetTaskSummary(task): task_flags += 'P' if hasattr(task, "suspend_count") and int(task.suspend_count) > 0: task_flags += 'S' - if hasattr(task, "imp_receiver") and int(task.imp_receiver) == 1: - task_flags += 'R' - if hasattr(task, "imp_donor") and int(task.imp_donor) == 1: - task_flags += 'D' - if hasattr(task, "task_imp_assertcnt") and int(task.task_imp_assertcnt) > 0: - task_flags += 'B' + if hasattr(task, 'task_imp_base') and unsigned(task.task_imp_base): + tib = task.task_imp_base + if int(tib.iit_receiver) == 1: + task_flags += 'R' + if int(tib.iit_donor) == 1: + task_flags += 'D' + if int(tib.iit_assertcnt) > 0: + task_flags += 'B' + + # check if corpse flag is set + if unsigned(task.t_flags) & 0x20: + task_flags += 'C' + if unsigned(task.t_flags) & 0x40: + task_flags += 'P' + out_string += format_string.format(task, task.map, task.itk_space, thread_count, task_flags) + if showcorpse is True and unsigned(task.corpse_info) != 0: + out_string += " " + GetKCDataSummary(task.corpse_info) return out_string @lldb_type_summary(['thread *', 'thread_t']) -@header("{0: <24s} {1: <10s} {2: <20s} {3: <6s} {4: <10s} {5: <5s} {6: <20s} {7: <45s} {8: <20s} {9: <20s}".format('thread', 'thread_id', 'processor', 'pri', 'io_policy', 'state', 'wait_queue', 'wait_event', 'wmesg', 'thread_name')) +@header("{0: <24s} {1: <10s} {2: <20s} {3: <6s} {4: <6s} {5: <15s} {6: <15s} {7: <8s} {8: <12s} {9: <32s} {10: <20s} {11: <20s} {12: <20s}".format('thread', 'thread_id', 'processor', 'base', 'pri', 'sched_mode', 'io_policy', 'state', 'ast', 'waitq', 'wait_event', 'wmesg', 'thread_name')) def GetThreadSummary(thread): """ Summarize the thread structure. It decodes the wait state and waitevents from the data in the struct. params: thread: value - value objecte representing a thread in kernel returns: str - summary of a thread + + State flags: + W - WAIT + S - SUSP + R - RUN + U - Uninterruptible + H - Terminated + A - Terminated and on termination queue + I - Idle thread + C - Crashed thread + + policy flags: + B - darwinbg + L - lowpri cpu + T - IO throttle + P - IO passive + D - Terminated """ out_string = "" - format_string = "{0: <24s} {1: <10s} {2: <20s} {3: <6s} {4: <10s} {5: <5s} {6: <20s} {7: <45s} {8: <20s} {9: <20s}" + format_string = "{0: <24s} {1: <10s} {2: <20s} {3: <6s} {4: <6s} {5: <15s} {6: <15s} {7: <8s} {8: <12s} {9: <32s} {10: <20s} {11: <20s} {12: <20s}" thread_ptr_str = str("{0: <#020x}".format(thread)) if int(thread.static_param) : thread_ptr_str+="[WQ]" thread_id = hex(thread.thread_id) thread_name = '' processor = hex(thread.last_processor) + base_priority = str(int(thread.base_pri)) sched_priority = str(int(thread.sched_pri)) + sched_mode = '' + mode = str(thread.sched_mode) + if "TIMESHARE" in mode: + sched_mode+="timeshare" + elif "FIXED" in mode: + sched_mode+="fixed" + elif "REALTIME" in mode: + sched_mode+="realtime" + + if (unsigned(thread.bound_processor) != 0): + sched_mode+=" bound" + + # TH_SFLAG_THROTTLED + if (unsigned(thread.sched_flags) & 0x0004): + sched_mode+=" BG" io_policy_str = "" if int(thread.uthread) != 0: @@ -176,16 +318,18 @@ def GetThreadSummary(thread): io_policy_str += "D" state = int(thread.state) - thread_state_chars = {0:'', 1:'W', 2:'S', 4:'R', 8:'U', 16:'H', 32:'A', 64:'P', 128:'I'} + thread_state_chars = {0x0:'', 0x1:'W', 0x2:'S', 0x4:'R', 0x8:'U', 0x10:'H', 0x20:'A', 0x40:'P', 0x80:'I'} state_str = '' - state_str += thread_state_chars[int(state & 0x1)] - state_str += thread_state_chars[int(state & 0x2)] - state_str += thread_state_chars[int(state & 0x4)] - state_str += thread_state_chars[int(state & 0x8)] - state_str += thread_state_chars[int(state & 0x10)] - state_str += thread_state_chars[int(state & 0x20)] - state_str += thread_state_chars[int(state & 0x40)] - state_str += thread_state_chars[int(state & 0x80)] + mask = 0x1 + while mask <= 0x80 : + state_str += thread_state_chars[int(state & mask)] + mask = mask << 1 + + if int(thread.inspection): + state_str += 'C' + + ast = int(thread.ast) | int(thread.reason) + ast_str = GetASTSummary(ast) #wait queue information wait_queue_str = '' @@ -193,7 +337,7 @@ def GetThreadSummary(thread): wait_message = '' if ( state & 0x1 ) != 0: #we need to look at the waitqueue as well - wait_queue_str = str("{0: <#020x}".format(int(hex(thread.wait_queue), 16))) + wait_queue_str = str("{0: <#020x}".format(int(hex(thread.waitq), 16))) wait_event_str = str("{0: <#020x}".format(int(hex(thread.wait_event), 16))) wait_event_str_sym = kern.Symbolicate(int(hex(thread.wait_event), 16)) if len(wait_event_str_sym) > 0: @@ -203,12 +347,215 @@ def GetThreadSummary(thread): if int(uthread.uu_wmesg) != 0: wait_message = str(Cast(uthread.uu_wmesg, 'char *')) - out_string += format_string.format(thread_ptr_str, thread_id, processor, sched_priority, io_policy_str, state_str, wait_queue_str, wait_event_str, wait_message, thread_name ) + out_string += format_string.format(thread_ptr_str, thread_id, processor, base_priority, sched_priority, sched_mode, io_policy_str, state_str, ast_str, wait_queue_str, wait_event_str, wait_message, thread_name) return out_string - -@lldb_type_summary(['proc']) +def GetTaskRoleString(role): + role_strs = { + 0 : "TASK_UNSPECIFIED", + 1 : "TASK_FOREGROUND_APPLICATION", + 2 : "TASK_BACKGROUND_APPLICATION", + 3 : "TASK_CONTROL_APPLICATION", + 4 : "TASK_GRAPHICS_SERVER", + 5 : "TASK_THROTTLE_APPLICATION", + 6 : "TASK_NONUI_APPLICATION", + 7 : "TASK_DEFAULT_APPLICATION", + } + return role_strs[int(role)] + +def GetCoalitionFlagString(coal): + flags = [] + if (coal.privileged): + flags.append('privileged') + if (coal.termrequested): + flags.append('termrequested') + if (coal.terminated): + flags.append('terminated') + if (coal.reaped): + flags.append('reaped') + if (coal.notified): + flags.append('notified') + return "|".join(flags) + +def GetCoalitionTasks(queue, coal_type, thread_details=False): + sfi_strs = { + 0x0 : "SFI_CLASS_UNSPECIFIED", + 0x1 : "SFI_CLASS_DARWIN_BG", + 0x2 : "SFI_CLASS_APP_NAP", + 0x3 : "SFI_CLASS_MANAGED_FOCAL", + 0x4 : "SFI_CLASS_MANAGED_NONFOCAL", + 0x5 : "SFI_CLASS_DEFAULT_FOCAL", + 0x6 : "SFI_CLASS_DEFAULT_NONFOCAL", + 0x7 : "SFI_CLASS_KERNEL", + 0x8 : "SFI_CLASS_OPTED_OUT", + 0x9 : "SFI_CLASS_UTILITY", + 0xA : "SFI_CLASS_LEGACY_FOCAL", + 0xB : "SFI_CLASS_LEGACY_NONFOCAL", + 0xC : "SFI_CLASS_USER_INITIATED_FOCAL", + 0xD : "SFI_CLASS_USER_INITIATED_NONFOCAL", + 0xE : "SFI_CLASS_USER_INTERACTIVE_FOCAL", + 0xF : "SFI_CLASS_USER_INTERACTIVE_NONFOCAL", + 0x10 : "SFI_CLASS_MAINTENANCE", + } + tasks = [] + field_name = 'task_coalition' + for task in IterateLinkageChain(queue, 'task *', field_name, coal_type * sizeof('queue_chain_t')): + task_str = "({0: ): + COALITION_TYPE_RESOURCE + COALITION_TYPE_JETSAM + """ + if type == 0: # COALITION_TYPE_RESOURCE + return 'RESOURCE' + if type == 1: + return 'JETSAM' + return '' + +def GetResourceCoalitionSummary(coal, verbose=False): + """ Summarize a resource coalition + """ + out_string = "Resource Coalition:\n\t Ledger:\n" + thread_details = False + if config['verbosity'] > vSCRIPT: + thread_details = True + ledgerp = coal.r.ledger + if verbose and unsigned(ledgerp) != 0: + i = 0 + while i != ledgerp.l_template.lt_cnt: + out_string += "\t\t" + out_string += GetLedgerEntrySummary(kern.globals.task_ledger_template, ledgerp.l_entries[i], i) + i = i + 1 + out_string += "\t bytesread {0: vSCRIPT: + thread_details = True + if unsigned(coal.j.leader) == 0: + out_string += "\n\t NO Leader!" + else: + out_string += "\n\t Leader:\n\t\t" + out_string += "({0: " + typestr = GetCoalitionTypeString(coal.type) + flagstr = GetCoalitionFlagString(coal) + out_string = "" + out_string += "Coalition {c: <#020x}\n\tID {c.id: + """ + verbose = False + if config['verbosity'] > vHUMAN: + verbose = True + if not cmd_args: + print "No arguments passed" + print ShowCoalitionInfo.__doc__ + return False + coal = kern.GetValueFromAddress(cmd_args[0], 'coalition *') + if not coal: + print "unknown arguments:", str(cmd_args) + return False + print GetCoalitionInfo(coal, verbose) + +# EndMacro: showcoalitioninfo + +# Macro: showallcoalitions + +@lldb_command('showallcoalitions') +def ShowAllCoalitions(cmd_args=None): + """ Print a summary listing of all the coalitions + """ + global kern + print GetCoalitionSummary.header + for c in kern.coalitions: + print GetCoalitionSummary(c) + +# EndMacro: showallcoalitions + +# Macro: showtaskcoalitions + +@lldb_command('showtaskcoalitions', 'F:') +def ShowTaskCoalitions(cmd_args=None, cmd_options={}): + """ + """ + task_list = [] + if "-F" in cmd_options: + task_list = FindTasksByName(cmd_options["-F"]) + elif cmd_args: + t = kern.GetValueFromAddress(cmd_args[0], 'task *') + task_list.append(t) + else: + raise ArgumentError("No arguments passed") + + if len(task_list) > 0: + print GetCoalitionSummary.header + for task in task_list: + print GetCoalitionSummary(task.coalition[0]) + print GetCoalitionSummary(task.coalition[1]) + +# EndMacro: showtaskcoalitions + +@lldb_type_summary(['proc', 'proc *']) @header("{0: >6s} {1: ^20s} {2: >14s} {3: ^10s} {4: <20s}".format("pid", "process", "io_policy", "wq_state", "command")) def GetProcSummary(proc): """ Summarize the process data. @@ -274,6 +621,63 @@ def GetProcSummary(proc): out_string += format_string.format(pid, proc_addr, " ".join([proc_rage_str, io_policy_str]), wq_num_threads, wq_idle_threads, wq_req_threads, process_name) return out_string +@lldb_type_summary(['tty_dev_t', 'tty_dev_t *']) +@header("{0: <20s} {1: <10s} {2: <10s} {3: <15s} {4: <15s} {5: <15s} {6: <15s}".format("tty_dev","master", "slave", "open", "free", "name", "revoke")) +def GetTTYDevSummary(tty_dev): + """ Summarizes the important fields in tty_dev_t structure. + params: tty_dev: value - value object representing a tty_dev_t in kernel + returns: str - summary of the tty_dev + """ + out_string = "" + format_string = "{0: <#020x} {1: <#010x} {2: <#010x} {3: <15s} {4: <15s} {5: <15s} {6: <15s}" + open_fn = kern.Symbolicate(int(hex(tty_dev.open), 16)) + free_fn = kern.Symbolicate(int(hex(tty_dev.free), 16)) + name_fn = kern.Symbolicate(int(hex(tty_dev.name), 16)) + revoke_fn = kern.Symbolicate(int(hex(tty_dev.revoke), 16)) + out_string += format_string.format(tty_dev, tty_dev.master, tty_dev.slave, open_fn, free_fn, name_fn, revoke_fn) + return out_string + +@lldb_type_summary(['kqueue *']) +@header("{: <20s} {: <20s} {: <6s} {: <20s} {: <10s}".format('kqueue', 'process', '#events', 'wqs', 'state')) +def GetKQueueSummary(kq): + """ summarizes kqueue information + returns: str - summary of kqueue + """ + out_string = "" + format_string = "{o: <#020x} {o.kq_p: <#020x} {o.kq_count: <6d} {o.kq_wqs: <#020x} {st_str: <10s}" + state = int(kq.kq_state) + state_str = '' + mask = 0x1 + while mask <= 0x80 : + if int(state & mask): + state_str += ' ' + xnudefines.kq_state_strings[int(state & mask)] + mask = mask << 1 + out_string += format_string.format(o=kq, st_str=state_str) + out_string += "\n" + GetKnoteSummary.header + for kn in IterateTAILQ_HEAD(kq.kq_head, 'kn_tqe'): + out_string += "\n" + GetKnoteSummary(kn) + return out_string + +@lldb_type_summary(['knote *']) +@header("{0: <20s} {1: <10s} {2: <10s} {3: <20s} {4: <20s} {5: <30s}".format('knote', 'ident', 'kev_flags', 'kn_kq', 'filtops', ' status')) +def GetKnoteSummary(kn): + """ Summarizes a knote and related information + returns: str - summary of knote + """ + out_string = "" + format_string = "{o: <#020x} {o.kn_kevent.ident: <#010X} {o.kn_kevent.flags: <#010X} {o.kn_kq: <#020X} {ops_str: <20s} {st_str: <30s}" + state = unsigned(kn.kn_status) + fops_str = kern.Symbolicate(unsigned(kn.kn_fop)) + mask = 0x1 + status_desc = '' + while mask <= 0x40: + if state & mask: + status_desc += ' ' + xnudefines.kn_state_strings[int(state & mask)] + mask = mask << 1 + + out_string += format_string.format(o=kn, st_str=status_desc, ops_str=fops_str) + return out_string + # Macro: showtask @lldb_command('showtask', 'F:') @@ -418,6 +822,66 @@ def ShowProcFiles(cmd_args=None): #EndMacro: showprocfiles + +def GetProcKqueues(proc): + filetype_KQUEUE = 5 + + proc_filedesc = proc.p_fd + proc_lastfile = unsigned(proc_filedesc.fd_lastfile) + proc_ofiles = proc_filedesc.fd_ofiles + + queues = list() + + if unsigned(proc_ofiles) == 0: + return queues + + count = 0 + + while count <= proc_lastfile: + if unsigned(proc_ofiles[count]) != 0: + proc_fd_flags = proc_ofiles[count].f_flags + proc_fd_fglob = proc_ofiles[count].f_fglob + proc_fd_ftype = unsigned(proc_fd_fglob.fg_ops.fo_type) + if proc_fd_ftype == filetype_KQUEUE: + q = Cast(proc_fd_fglob.fg_data, 'struct kqueue *') + queues.append(q) + count += 1 + + return queues + +def GetAllKqueues(): + for t in kern.tasks: + if unsigned(t.bsd_info) == 0: + continue + pval = Cast(t.bsd_info, 'proc *') + for kq in GetProcKqueues(pval): + yield kq + +#Macro: showallkqueues +@lldb_command('showallkqueues' ,'') +def ShowAllKqueues(cmd_args=[], cmd_options={}): + """ Display a summary of all the kqueues in the system """ + for kq in GetAllKqueues(): + print GetKQueueSummary.header + print GetKQueueSummary(kq) + print "\n\n" +#EndMacro: showallkqueues + +#Macro: showkqueue +@lldb_command('showkqueue' ,'') +def ShowKQueue(cmd_args=[], cmd_options={}): + """ Given a struct kqueue pointer, display the summary of the kqueue + Usage: (lldb) showkqueue + """ + if not cmd_args: + raise ArgumentError('Invalid arguments') + + kq = kern.GetValueFromAddress(cmd_args[0], 'struct kqueue *') + print GetKQueueSummary.header + print GetKQueueSummary(kq) + +#EndMacro: showkqueue + #Macro: showtty @lldb_command('showtty') @@ -488,6 +952,58 @@ def ShowTTY(cmd_args=None): #EndMacro: showtty +#Macro showallttydevs + +@lldb_command('showallttydevs') +def ShowAllTTYDevs(cmd_args=[], cmd_options={}): + """ Show a list of ttydevs registered in the system. + Usage: + (lldb)showallttydevs + """ + tty_dev_head = kern.globals.tty_dev_head + tty_dev = tty_dev_head + print GetTTYDevSummary.header + while unsigned(tty_dev) != 0: + print GetTTYDevSummary(tty_dev) + tty_dev = tty_dev.next + return "" + +#EndMacro: showallttydevs + +#Macro: dumpthread_terminate_queue + +@lldb_command('dumpthread_terminate_queue') +def DumpThreadTerminateQueue(cmd_args=None): + """ Displays the contents of the specified call_entry queue. + Usage: dumpthread_terminate_queue + """ + + count = 0 + print GetThreadSummary.header + for th in IterateQueue(addressof(kern.globals.thread_terminate_queue), 'struct thread *', 'q_link'): + print GetThreadSummary(th) + count += 1 + print "{0: """ if not cmd_args: - print DumpCallQueue.__doc__ - return + raise ArgumentError("Invalid arguments") + print "{0: <18s} {1: <18s} {2: <18s} {3: <64s} {4: <18s}".format('CALL_ENTRY', 'PARAM0', 'PARAM1', 'DEADLINE', 'FUNC') callhead = kern.GetValueFromAddress(cmd_args[0], 'queue_head_t *') count = 0 @@ -510,8 +1026,23 @@ def DumpCallQueue(cmd_args=None): #EndMacro: dumpcallqueue -@lldb_command('showalltasks') -def ShowAllTasks(cmd_args=None): +@lldb_command('showalltasklogicalwrites') +def ShowAllTaskIOStats(cmd_args=None): + """ Commad to print I/O stats for all tasks + """ + print "{0: <20s} {1: <20s} {2: <20s} {3: <20s} {4: <20s} {5: <20s}".format("task", "Immediate Writes", "Deferred Writes", "Invalidated Writes", "Metadata Writes", "name") + for t in kern.tasks: + pval = Cast(t.bsd_info, 'proc *') + print "{0: <#18x} {1: >20d} {2: >20d} {3: >20d} {4: >20d} {5: <20s}".format(t, + t.task_immediate_writes, + t.task_deferred_writes, + t.task_invalidated_writes, + t.task_metadata_writes, + str(pval.p_comm)) + + +@lldb_command('showalltasks','C') +def ShowAllTasks(cmd_args=None, cmd_options={}): """ Routine to print a summary listing of all the tasks wq_state -> reports "number of workq threads", "number of scheduled workq threads", "number of pending work items" if "number of pending work items" seems stuck at non-zero, it may indicate that the workqueue mechanism is hung @@ -519,12 +1050,21 @@ def ShowAllTasks(cmd_args=None): NORM - normal I/O explicitly requested (this is the default) PASS - passive I/O requested (i.e. I/Os do not affect throttling decisions) THROT - throttled I/O requested (i.e. thread/task may be throttled after each I/O completes) + Usage: (lldb) showalltasks -C : describe the corpse structure """ global kern - print GetTaskSummary.header + " " + GetProcSummary.header + extra_hdr = '' + showcorpse = False + if '-C' in cmd_options: + showcorpse = True + extra_hdr += " " + GetKCDataSummary.header + + print GetTaskSummary.header + extra_hdr + " " + GetProcSummary.header for t in kern.tasks: pval = Cast(t.bsd_info, 'proc *') - print GetTaskSummary(t) +" "+ GetProcSummary(pval) + out_str = GetTaskSummary(t, showcorpse) + " " + GetProcSummary(pval) + print out_str + ZombTasks() @lldb_command('showterminatedtasks') def ShowTerminatedTasks(cmd_args=None): @@ -611,6 +1151,12 @@ def ShowAllThreads(cmd_args = None): for t in kern.tasks: ShowTaskThreads([str(int(t))]) print " \n" + + for t in kern.terminated_tasks: + print "Terminated: \n" + ShowTaskThreads([str(int(t))]) + print " \n" + return @lldb_command('showtaskthreads', "F:") @@ -686,6 +1232,38 @@ def SwitchToAct(cmd_args=None): if not LazyTarget.GetProcess().SetSelectedThread(lldbthread): print "Failed to switch thread." return + +@lldb_command('switchtoregs') +def SwitchToRegs(cmd_args=None): + """ Routine to switch to a register state. + Usage: (lldb) switchtoregs + This command creates a fake thread in lldb with the saved register state. + Note: This command ONLY works for ARM based kernel setup. + """ + + if cmd_args == None or len(cmd_args) < 1: + raise ArgumentError("No arguments passed") + + lldb_process = LazyTarget.GetProcess() + + saved_state = ArgumentStringToInt(cmd_args[0]) + # any change to this logic requires change in operating_system.py as well + fake_thread_id = 0xdead0000 | (saved_state & ~0xffff0000) + fake_thread_id = fake_thread_id & 0xdeadffff + lldb_process.CreateOSPluginThread(0xdeadbeef, saved_state) + lldbthread = lldb_process.GetThreadByID(int(fake_thread_id)) + + if not lldbthread.IsValid(): + print "Failed to create thread" + return + + lldb_process.selected_thread = lldbthread + if not lldb_process.SetSelectedThread(lldbthread): + print "Failed to switch thread" + print "Switched to Fake thread created from register state at 0x%x" % saved_state + + + # Macro: showallstacks @lldb_command('showallstacks') def ShowAllStacks(cmd_args=None): @@ -693,7 +1271,8 @@ def ShowAllStacks(cmd_args=None): """ for t in kern.tasks: ShowTaskStacks(t) - print " \n" + print " \n" + ZombStacks() return # EndMacro: showallstacks @@ -706,7 +1285,7 @@ def ShowCurrentStacks(cmd_args=None): processor_list = kern.GetGlobalVariable('processor_list') current_processor = processor_list while unsigned(current_processor) > 0: - print "\nProcessor {: <#020x} State {: #04x})".format(current_processor, int(current_processor.state), int(current_processor.cpu_id)) + print "\n" + GetProcessorSummary(current_processor) active_thread = current_processor.active_thread if unsigned(active_thread) != 0 : task_val = active_thread.task @@ -727,7 +1306,7 @@ def ShowCurrentThreads(cmd_args=None): processor_list = kern.GetGlobalVariable('processor_list') current_processor = processor_list while unsigned(current_processor) > 0: - print "Processor {: <#020x} State {: #04x})".format(current_processor, int(current_processor.state), int(current_processor.cpu_id)) + print GetProcessorSummary(current_processor) active_thread = current_processor.active_thread if unsigned(active_thread) != 0 : task_val = active_thread.task @@ -752,7 +1331,7 @@ def GetFullBackTrace(frame_addr, verbosity = vHUMAN, prefix = ""): # lldb unable to find symbol for _mh_execute_header mh_execute_addr = int(lldb_run_command('p/x (uintptr_t *)&_mh_execute_header').split('=')[-1].strip(), 16) while frame_ptr and frame_ptr != previous_frame_ptr and bt_count < 128: - if (kern.arch != 'arm' and frame_ptr < mh_execute_addr) or (kern.arch == 'arm' and frame_ptr > mh_execute_addr): + if (kern.arch not in ('arm', 'arm64') and frame_ptr < mh_execute_addr) or (kern.arch in ('arm', 'arm64') and frame_ptr > mh_execute_addr): break pc_val = kern.GetValueFromAddress(frame_ptr + kern.ptrsize,'uintptr_t *') pc_val = unsigned(dereference(pc_val)) @@ -770,13 +1349,37 @@ def GetFullBackTrace(frame_addr, verbosity = vHUMAN, prefix = ""): def FullBackTrace(cmd_args=[]): """ Show full backtrace across the interrupt boundary. Syntax: fullbt - Example: kfullbt `$rbp` + Example: fullbt `$rbp` """ if len(cmd_args) < 1: print FullBackTrace.__doc__ return False print GetFullBackTrace(ArgumentStringToInt(cmd_args[0]), prefix="\t") +@lldb_command('fullbtall') +def FullBackTraceAll(cmd_args=[]): + """ Show full backtrace across the interrupt boundary for threads running on all processors. + Syntax: fullbtall + Example: fullbtall + """ + for processor in IterateLinkedList(kern.globals.processor_list, 'processor_list') : + print "\n" + GetProcessorSummary(processor) + active_thread = processor.active_thread + if unsigned(active_thread) != 0 : + task_val = active_thread.task + proc_val = Cast(task_val.bsd_info, 'proc *') + print GetTaskSummary.header + " " + GetProcSummary.header + print GetTaskSummary(task_val) + " " + GetProcSummary(proc_val) + print "\t" + GetThreadSummary.header + print "\t" + GetThreadSummary(active_thread) + print "\tBacktrace:" + + ThreadVal = GetLLDBThreadForKernelThread(active_thread) + + FramePtr = ThreadVal.frames[0].GetFP() + + print GetFullBackTrace(unsigned(FramePtr), prefix="\t") + @lldb_command('symbolicate') def SymbolicateAddress(cmd_args=[]): @@ -866,42 +1469,119 @@ def GetProcessorSummary(processor): params: processor - value representing struct processor * return: str - representing the details of given processor """ - out_str = "Processor {: <#012x} ".format(processor) - out_str += "State {:d} (cpu_id {:#x})\n".format(processor.state, processor.cpu_id) + + processor_state_str = "INVALID" + processor_state = int(processor.state) + + processor_states = { + 0: 'OFF_LINE', + 1: 'SHUTDOWN', + 2: 'START', + # 3 (formerly INACTIVE) + 4: 'IDLE', + 5: 'DISPATCHING', + 6: 'RUNNING' + } + + if processor_state in processor_states: + processor_state_str = "{0: <11s} ".format(processor_states[processor_state]) + + processor_recommended_str = "" + if int(processor.is_recommended) == 0: + processor_recommended_str = " (not recommended)" + + ast = 0 + preemption_disable = 0 + preemption_disable_str = "" + + if kern.arch == 'x86_64': + cpu_data = kern.globals.cpu_data_ptr[processor.cpu_id] + if (cpu_data != 0) : + ast = cpu_data.cpu_pending_ast + preemption_disable = cpu_data.cpu_preemption_level + # On arm64, it's kern.globals.CpuDataEntries[processor.cpu_id].cpu_data_vaddr + # but LLDB can't find CpuDataEntries... + + ast_str = GetASTSummary(ast) + + if (preemption_disable != 0) : + preemption_disable_str = "Preemption Disabled" + + out_str = "Processor {: <#018x} cpu_id {:>#4x} AST: {:<6s} State {: + """ + out_str = '' + runq = kern.GetValueFromAddress(cmd_args[0], 'struct run_queue *') + out_str += GetRunQSummary(runq) + print out_str + def GetRunQSummary(runq): """ Internal function to print summary of run_queue params: runq - value representing struct run_queue * return: str - representing the details of given run_queue """ - out_str = " Priority Run Queue Info: Count {: <10d}\n".format(runq.count) + out_str = " runq: count {: <10d} highq: {: <10d} urgency {: <10d}\n".format(runq.count, runq.highq, runq.urgency) + runq_queue_i = 0 runq_queue_count = sizeof(runq.queues)/sizeof(runq.queues[0]) - while runq.count and (runq_queue_i < runq_queue_count): + + for runq_queue_i in range(runq_queue_count) : runq_queue_head = addressof(runq.queues[runq_queue_i]) runq_queue_p = runq_queue_head.next + if unsigned(runq_queue_p) != unsigned(runq_queue_head): runq_queue_this_count = 0 - while runq_queue_p != runq_queue_head: - runq_queue_this_count = runq_queue_this_count + 1 - runq_queue_p_thread = Cast(runq_queue_p, 'thread_t') - # Get the task information - out_str += GetTaskSummary.header + " " + GetProcSummary.header - pval = Cast(runq_queue_p_thread.task.bsd_info, 'proc *') - out_str += GetTaskSummary(runq_queue_p_thread.task) +" "+ GetProcSummary(pval) - # Get the thread information with related stack traces - out_str += GetThreadSummary.header + GetThreadSummary(runq_queue_p_thread) - out_str += GetThreadBackTrace(LazyTarget.GetProcess().GetThreadByID(int(runq_queue_p_thread.thread_id)), - prefix="\t") - runq_queue_p = runq_queue_p.next - - out_str += " Queue Priority {: <3d} [{: <#012x}] Count {:d}\n".format(runq_queue_i, - runq_queue_head, runq_queue_this_count) - - runq_queue_i = runq_queue_i + 1 + + for thread in IterateQueue(runq_queue_head, "thread_t", "links"): + runq_queue_this_count += 1 + + out_str += " Queue [{: <#012x}] Priority {: <3d} count {:d}\n".format(runq_queue_head, runq_queue_i, runq_queue_this_count) + out_str += "\t" + GetThreadSummary.header + "\n" + for thread in IterateQueue(runq_queue_head, "thread_t", "links"): + out_str += "\t" + GetThreadSummary(thread) + "\n" + if config['verbosity'] > vHUMAN : + out_str += "\t" + GetThreadBackTrace(thread, prefix="\t\t") + "\n" return out_str + def GetGrrrSummary(grrr_runq): """ Internal function to print summary of grrr_run_queue params: grrr_runq - value representing struct grrr_run_queue * @@ -911,26 +1591,32 @@ def GetGrrrSummary(grrr_runq): grrr_runq.weight, grrr_runq.current_group) grrr_group_i = 0 grrr_group_count = sizeof(grrr_runq.groups)/sizeof(grrr_runq.groups[0]) - while grrr_runq.count and (grrr_group_i < grrr_group_count): + for grrr_group_i in range(grrr_group_count) : grrr_group = addressof(grrr_runq.groups[grrr_group_i]) - runq_queue_p = runq_queue_head.next if grrr_group.count > 0: out_str += " Group {: <3d} [{: <#012x}] ".format(grrr_group.index, grrr_group) out_str += "Count {:d} Weight {:d}\n".format(grrr_group.count, grrr_group.weight) grrr_group_client_head = addressof(grrr_group.clients) - grrr_group_client = grrr_group_client_head.next - while grrr_group_client != grrr_group_client_head: - grrr_group_client_thread = Cast(grrr_group_client, 'thread_t') - # Get the task information - out_str += GetTaskSummary.header + " " + GetProcSummary.header - pval = Cast(grrr_group_client_thread.task.bsd_info, 'proc *') - out_str += GetTaskSummary(grrr_group_client_thread.task) +" "+ GetProcSummary(pval) - # Get the thread information with related stack traces - out_str += GetThreadSummary.header + GetThreadSummary(grrr_group_client_thread) - out_str += GetThreadBackTrace(LazyTarget.GetProcess().GetThreadByID(int(grrr_group_client_thread.thread_id)), - prefix="\t") - grrr_group_client = grrr_group_client.next - grrr_group_i = grrr_group_i + 1 + out_str += GetThreadSummary.header + for thread in IterateQueue(grrr_group_client_head, "thread_t", "links"): + out_str += "\t" + GetThreadSummary(thread) + "\n" + if config['verbosity'] > vHUMAN : + out_str += "\t" + GetThreadBackTrace(thread, prefix="\t\t") + "\n" + return out_str + +def ShowNextThread(processor): + out_str = "" + if (processor.next_thread != 0) : + out_str += " " + "Next thread:\n" + out_str += "\t" + GetThreadSummary.header + "\n" + out_str += "\t" + GetThreadSummary(processor.next_thread) + "\n" + return out_str + +def ShowActiveThread(processor): + out_str = "" + if (processor.active_thread != 0) : + out_str += "\t" + GetThreadSummary.header + "\n" + out_str += "\t" + GetThreadSummary(processor.active_thread) + "\n" return out_str @lldb_command('showallprocessors') @@ -942,100 +1628,119 @@ def ShowAllProcessors(cmd_args=None): show_grrr = 0 show_priority_runq = 0 show_priority_pset_runq = 0 - show_fairshare_grrr = 0 - show_fairshare_list = 0 - sched_enum_val = kern.globals._sched_enum + show_group_pset_runq = 0 + sched_string = str(kern.globals.sched_current_dispatch.sched_name) - if sched_enum_val == 1: + if sched_string == "traditional": show_priority_runq = 1 - show_fairshare_list = 1 - elif sched_enum_val == 2: + elif sched_string == "traditional_with_pset_runqueue": show_priority_pset_runq = 1 - show_fairshare_list = 1 - elif sched_enum_val == 4: + elif sched_string == "grrr": show_grrr = 1 - show_fairshare_grrr = 1 - elif sched_enum_val == 5: + elif sched_string == "multiq": show_priority_runq = 1 - show_fairshare_list = 1 - elif sched_enum_val == 6: - show_priority_pset_runq = 1 - show_fairshare_list = 1 + show_group_pset_runq = 1 + elif sched_string == "dualq": + show_priority_pset_runq = 1 + show_priority_runq = 1 + else : + print "Unknown sched_string {:s}".format(sched_string) out_str = '' - while pset: + + out_str += "Scheduler: {:s} ({:s})\n".format(sched_string, + kern.Symbolicate(unsigned(kern.globals.sched_current_dispatch))) + + out_str += "Runnable threads: {:d} Timeshare threads: {:d} Background threads: {:d}\n".format( + kern.globals.sched_run_count, kern.globals.sched_share_count, kern.globals.sched_background_count) + + if show_group_pset_runq: + # Create a group->task mapping + task_map = {} + for task in kern.tasks: + task_map[unsigned(task.sched_group)] = task + for task in kern.terminated_tasks: + task_map[unsigned(task.sched_group)] = task + + while unsigned(pset) != 0: out_str += "Processor Set {: <#012x} Count {:d} (cpu_id {:<#x}-{:<#x})\n".format(pset, pset.cpu_set_count, pset.cpu_set_low, pset.cpu_set_hi) + + if show_priority_pset_runq: + runq = pset.pset_runq + out_str += GetRunQSummary(runq) + + if show_group_pset_runq: + out_str += "Main Runq:\n" + runq = pset.pset_runq + out_str += GetGroupSetSummary(runq, task_map) + out_str += "All Groups:\n" + # TODO: Possibly output task header for each group + for group in IterateQueue(kern.globals.sched_groups, "sched_group_t", "sched_groups"): + if (group.runq.count != 0) : + task = task_map.get(unsigned(group), "Unknown task!") + out_str += "Group {: <#012x} Task {: <#012x}\n".format(unsigned(group), unsigned(task)) + out_str += GetRunQSummary(group.runq) + out_str += " Active Processors:\n" - active_queue_head = addressof(pset.active_queue) - active_elt = active_queue_head.next - while active_elt != active_queue_head: - processor = Cast(active_elt, 'processor *') + for processor in IterateQueue(pset.active_queue, "processor_t", "processor_queue"): out_str += " " out_str += GetProcessorSummary(processor) + out_str += ShowActiveThread(processor) + out_str += ShowNextThread(processor) + if show_priority_runq: - runq = addressof(processor.runq) + runq = processor.runq out_str += GetRunQSummary(runq) if show_grrr: - grrr_runq = addressof(processor.grrr_runq) + grrr_runq = processor.grrr_runq out_str += GetGrrrSummary(grrr_runq) - - if processor.processor_meta and (processor.processor_meta.primary == - processor): - processor_meta_idle_head = addressof(processor.processor_meta.idle_queue) - processor_meta_idle = processor_meta_idle_head.next - while processor_meta_idle != processor_meta_idle_head: - out_str += " Idle Meta Processor: " - out_str += GetProcessorSummary(processor_meta_idle) - processor_meta_idle = processor_meta_idle.next - active_elt = active_elt.next out_str += " Idle Processors:\n" - idle_queue_head = addressof(pset.idle_queue) - idle_elt = idle_queue_head.next - while idle_elt != idle_queue_head: - processor = Cast(idle_elt, 'processor *') - out_str += " " - out_str += GetProcessorSummary(processor) - - if processor.processor_meta and (processor.processor_meta.primary == - processor): - processor_meta_idle_head = addressof(processor.processor_meta.idle_queue) - processor_meta_idle = processor_meta_idle_head.next - while processor_meta_idle != processor_meta_idle_head: - out_str += " Idle Meta Processor: " - out_str += GetProcessorSummary(processor_meta_idle) - processor_meta_idle = processor_meta_idle.next - idle_elt = idle_elt.next - - if show_priority_pset_runq: - runq = addressof(pset.pset_runq) - out_str += "\n" + GetRunQSummary(runq) + for processor in IterateQueue(pset.idle_queue, "processor_t", "processor_queue"): + out_str += " " + GetProcessorSummary(processor) + out_str += ShowActiveThread(processor) + out_str += ShowNextThread(processor) + + if show_priority_runq: + out_str += GetRunQSummary(processor.runq) + + out_str += " Idle Secondary Processors:\n" + for processor in IterateQueue(pset.idle_secondary_queue, "processor_t", "processor_queue"): + out_str += " " + GetProcessorSummary(processor) + out_str += ShowActiveThread(processor) + out_str += ShowNextThread(processor) + + if show_priority_runq: + out_str += GetRunQSummary(processor.runq) + pset = pset.pset_list - out_str += "\nRealtime Queue Count {:d}\n".format(kern.globals.rt_runq.count) - rt_runq_head = addressof(kern.globals.rt_runq.queue) - rt_runq_local = rt_runq_head.next - while rt_runq_local != rt_runq_head: - rt_runq_thread = Cast(rt_runq_local, 'thread *') - out_str += ShowTask([unsigned(rt_runq_thread.task)]) - out_str += ShowAct([unsigned(rt_runq_thread)]) - rt_runq_local = rt_runq_local.next + out_str += "\nRealtime Queue ({:<#012x}) Count {:d}\n".format(addressof(kern.globals.rt_runq.queue), kern.globals.rt_runq.count) + if kern.globals.rt_runq.count != 0: + out_str += "\t" + GetThreadSummary.header + "\n" + for rt_runq_thread in IterateQueue(kern.globals.rt_runq.queue, "thread_t", "links"): + out_str += "\t" + GetThreadSummary(rt_runq_thread) + "\n" + + out_str += "\nTerminate Queue: ({:<#012x})\n".format(addressof(kern.globals.thread_terminate_queue)) + first = False + for thread in IterateQueue(kern.globals.thread_terminate_queue, "thread_t", "links"): + if first: + out_str += "\t" + GetThreadSummary.header + "\n" + first = True + out_str += "\t" + GetThreadSummary(thread) + "\n" + + out_str += "\nCrashed Threads Queue: ({:<#012x})\n".format(addressof(kern.globals.crashed_threads_queue)) + first = False + for thread in IterateQueue(kern.globals.crashed_threads_queue, "thread_t", "links"): + if first: + out_str += "\t" + GetThreadSummary.header + "\n" + first = True + out_str += "\t" + GetThreadSummary(thread) + "\n" + + out_str += "\n" out_str += "\n" - if show_fairshare_list: - out_str += "Fair Share Queue Count {:d}\n".format(kern.globals.fs_runq.count) - fs_runq_head = addressof(kern.globals.fs_runq.queue) - fs_runq_local = fs_runq_head.next - while fs_runq_local != fs_runq_head: - fs_runq_thread = Cast(fs_runq, 'thread *') - out_str += ShowTask([unsigned(fs_runq_thread.task)]) - out_str += ShowAct([unsigned(rt_runq_thread)]) - fs_runq_local = fs_runq_local.next - if show_fairshare_grrr: - out_str += "Fair Share Queue Count {:d}\n".format(kern.globals.fs_grrr_runq.count) - fs_grrr = addressof(kern.globals.fs_grrr_runq) - out_str += GetGrrrSummary(fs_grrr) print out_str # EndMacro: showallprocessors @@ -1051,18 +1756,18 @@ def GetLedgerEntrySummary(ledger_template, ledger, i): lf_tracking_max = 0x4000 out_str = '' - now = kern.globals.sched_tick / 20 + now = unsigned(kern.globals.sched_tick) / 20 lim_pct = 0 - out_str += "{: >25s} {: unsigned(ledger.le_limit)): + if ((unsigned(ledger.le_credit) - unsigned(ledger.le_debit)) > unsigned(ledger.le_limit)): out_str += " X " else: out_str += " " @@ -1106,7 +1811,7 @@ def GetThreadLedgerSummary(thread_val): i = i + 1 return out_str -@header("{0: <15s} {1: >9s} {2: <2s} {3: >12s} {4: >9s} {5: >6s} {6: >8s} {7: <10s} {8: <9s} \ +@header("{0: <15s} {1: >16s} {2: <2s} {3: >15s} {4: >9s} {5: >6s} {6: >8s} {7: <10s} {8: <9s} \ {9: <12s} {10: <7s} {11: <15s} {12: <8s} {13: <9s} {14: <6s} {15: >6s}".format( "task [thread]", "entry", "#", "balance", "peakA", "(age)", "peakB", "(age)", "credit", "debit", "limit", "refill period", "lim pct", "warn pct", "over?", "flags")) @@ -1237,7 +1942,6 @@ def ShowAllTaskPolicy(cmd_args=None): ["t_int_gpu_deny", "gpudeny-int"], ["t_ext_gpu_deny", "gpudeny-ext"], ["t_role", "role"], - ["t_visibility", "vis"], ["t_tal_enabled", "tal-enabled"], ["t_base_latency_qos", "latency-base"], ["t_over_latency_qos", "latency-override"], @@ -1258,7 +1962,8 @@ def ShowAllTaskPolicy(cmd_args=None): ["t_sup_timer", "timer-throttling"], ["t_sup_disk", "disk-throttling"], ["t_sup_cpu_limit", "cpu-limits"], - ["t_sup_suspend", "suspend"] + ["t_sup_suspend", "suspend"], + ["t_sup_bg_sockets", "bg-sockets"] ] suppression="" @@ -1284,8 +1989,7 @@ def ShowAllTaskPolicy(cmd_args=None): ["t_latency_qos", "latency-qos"], ["t_through_qos", "throughput-qos"], ["t_sup_active", "suppression-active"], - ["t_role", "role"], - ["t_visibility", "vis"] + ["t_role", "role"] ] effective="" @@ -1316,5 +2020,51 @@ def ShowAllTaskPolicy(cmd_args=None): print "pended: " + pended +@lldb_type_summary(['wait_queue', 'wait_queue_t']) +@header("{: <20s} {: <20s} {: <15s} {:<5s} {:<5s} {: <20s}".format("waitq", "interlock", "policy", "members", "threads", "eventmask")) +def GetWaitQSummary(waitq): + """ Summarizes the important fields in task structure. + params: task: value - value object representing a task in kernel + returns: str - summary of the task + """ + out_string = "" + format_string = '{: <#020x} {: <#020x} {: <15s} {: <5d} {: <5d} {: <#020x}' + + wqtype = "" + + if (waitq.wq_fifo == 1) : + wqtype += "FIFO" + else : + wqtype += "PRIO" + + if (waitq.wq_prepost == 1) : + wqtype += "Prepost" + + if (waitq.wq_type == 0x3) : + wqtype += "Set" + elif (waitq.wq_type == 0x2) : + wqtype += "Queue" + else : + wqtype += "INVALID" + + out_string += format_string.format(waitq, unsigned(waitq.wq_interlock.lock_data), policy, 0, 0, unsigned(waitq.wq_eventmask)) + + out_string += "\n" + GetThreadSummary.header + + for thread in IterateQueue(waitq.wq_queue, "thread_t", "links"): + out_string += "\n" + GetThreadSummary(thread) + + return out_string + + +@lldb_command('showallsuspendedtasks', '') +def ShowSuspendedTasks(cmd_args=[], options={}): + """ Show a list of suspended tasks with their process name summary. + """ + print GetTaskSummary.header + ' ' + GetProcSummary.header + for t in kern.tasks: + if t.suspend_count > 0: + print GetTaskSummary(t) + ' ' + GetProcSummary(Cast(t.bsd_info, 'proc *')) + return True