X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/39236c6e673c41db228275375ab7fdb0f837b292..d9a64523371fa019c4575bb400cbbc3a50ac9903:/tools/lldbmacros/process.py diff --git a/tools/lldbmacros/process.py b/tools/lldbmacros/process.py old mode 100644 new mode 100755 index 11f9ef452..f37169a3b --- a/tools/lldbmacros/process.py +++ b/tools/lldbmacros/process.py @@ -1,13 +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 +import memory + +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. @@ -92,22 +122,95 @@ 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 + G - AST_GUARD + T - AST_TELEMETRY_USER + T - AST_TELEMETRY_KERNEL + T - AST_TELEMETRY_WINDOWED + S - AST_SFI + D - AST_DTRACE + I - AST_TELEMETRY_IO + E - AST_KEVENT + R - AST_REBALANCE + N - AST_UNQUIESCE + """ + 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', + 0x1000:'G', 0x2000:'T', 0x4000:'T', 0x8000:'T', 0x10000:'S', + 0x20000: 'D', 0x40000: 'I', 0x80000: 'E', 0x100000: 'R', 0x200000: 'N'} + state_str = '' + mask = 0x1 + while mask <= 0x80000: + 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 @@ -118,43 +221,96 @@ def GetTaskSummary(task): task_flags = '' if hasattr(task, "suppression_generation") and (int(task.suppression_generation) & 0x1) == 0x1: task_flags += 'P' + if hasattr(task, "effective_policy") and int(task.effective_policy.tep_sup_active) == 1: + task_flags += 'N' 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 +def GetThreadName(thread): + """ Get the name of a thread, if possible. Returns the empty string + otherwise. + """ + if int(thread.uthread) != 0: + uthread = Cast(thread.uthread, 'uthread *') + if int(uthread.pth_name) != 0 : + th_name_strval = Cast(uthread.pth_name, 'char *') + if len(str(th_name_strval)) > 0 : + return str(th_name_strval) + + return '' + @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 + 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 = "" + thread_name = GetThreadName(thread) if int(thread.uthread) != 0: uthread = Cast(thread.uthread, 'uthread *') - #check for thread name - if int(uthread.pth_name) != 0 : - th_name_strval = Cast(uthread.pth_name, 'char *') - if len(str(th_name_strval)) > 0 : - thread_name = str(th_name_strval) - + #check for io_policy flags if int(uthread.uu_flag) & 0x400: io_policy_str+='RAGE ' @@ -163,29 +319,28 @@ def GetThreadSummary(thread): io_policy_str = "" - if int(thread.effective_policy.darwinbg) != 0: + if int(thread.effective_policy.thep_darwinbg) != 0: io_policy_str += "B" - if int(thread.effective_policy.lowpri_cpu) != 0: - io_policy_str += "L" - - if int(thread.effective_policy.io_tier) != 0: + if int(thread.effective_policy.thep_io_tier) != 0: io_policy_str += "T" - if int(thread.effective_policy.io_passive) != 0: + if int(thread.effective_policy.thep_io_passive) != 0: io_policy_str += "P" - if int(thread.effective_policy.terminated) != 0: + if int(thread.effective_policy.thep_terminated) != 0: 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 +348,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 +358,253 @@ 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') + if (coal.efficient): + flags.append('efficient') + 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: + raise ArgumentError("No arguments passed") + 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: showallthreadgroups + +@lldb_type_summary(['struct thread_group *', 'thread_group *']) +@header("{0: <20s} {1: <5s} {2: <16s} {3: <5s} {4: <8s} {5: <20s}".format("thread_group", "id", "name", "refc", "flags", "recommendation")) +def GetThreadGroupSummary(tg): + if unsigned(tg) == 0: + return '{0: <#020x} {1: <5d} {2: <16s} {3: <5d} {4: <8s} {5: <20d}'.format(0, -1, "", -1, "", -1) + out_string = "" + format_string = '{0: <#020x} {1: <5d} {2: <16s} {3: <5d} {4: <8s} {5: <20d}' + tg_flags = '' + if (tg.tg_flags & 0x1): + tg_flags += 'E' + if (tg.tg_flags & 0x2): + tg_flags += 'U' + out_string += format_string.format(tg, tg.tg_id, tg.tg_name, tg.tg_refcount, tg_flags, tg.tg_recommendation) + return out_string + +@lldb_command('showallthreadgroups') +def ShowAllThreadGroups(cmd_args=None): + """ Print a summary listing of all thread groups + """ + global kern + print GetThreadGroupSummary.header + for tg in kern.thread_groups: + print GetThreadGroupSummary(tg) + +# EndMacro: showallthreadgroups + +# 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. @@ -236,23 +632,21 @@ def GetProcSummary(proc): io_policy_str = "" - if int(task.effective_policy.darwinbg) != 0: + if int(task.effective_policy.tep_darwinbg) != 0: io_policy_str += "B" - if int(task.effective_policy.lowpri_cpu) != 0: + if int(task.effective_policy.tep_lowpri_cpu) != 0: io_policy_str += "L" - if int(task.effective_policy.io_tier) != 0: + if int(task.effective_policy.tep_io_tier) != 0: io_policy_str += "T" - if int(task.effective_policy.io_passive) != 0: + if int(task.effective_policy.tep_io_passive) != 0: io_policy_str += "P" - if int(task.effective_policy.terminated) != 0: + if int(task.effective_policy.tep_terminated) != 0: io_policy_str += "D" - if int(task.effective_policy.t_suspended) != 0: - io_policy_str += "S" - if int(task.effective_policy.t_latency_qos) != 0: + if int(task.effective_policy.tep_latency_qos) != 0: io_policy_str += "Q" - if int(task.effective_policy.t_sup_active) != 0: + if int(task.effective_policy.tep_sup_active) != 0: io_policy_str += "A" @@ -271,9 +665,31 @@ def GetProcSummary(proc): wq_idle_threads = -1 wq_req_threads = -1 process_name = str(proc.p_comm) + if process_name == 'xpcproxy': + for thread in IterateQueue(task.threads, 'thread *', 'task_threads'): + thread_name = GetThreadName(thread) + if thread_name: + process_name += ' (' + thread_name + ')' + break 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 + # Macro: showtask @lldb_command('showtask', 'F:') @@ -309,9 +725,7 @@ def ShowPid(cmd_args=None): Usage: showpid """ if not cmd_args: - print "No arguments passed" - print ShowPid.__doc__ - return False + raise ArgumentError("No arguments passed") pidval = ArgumentStringToInt(cmd_args[0]) for t in kern.tasks: pval = Cast(t.bsd_info, 'proc *') @@ -330,9 +744,7 @@ def ShowProc(cmd_args=None): Usage: showproc
""" if not cmd_args: - print "No arguments passed" - print ShowProc.__doc__ - return False + raise ArgumentError("No arguments passed") pval = kern.GetValueFromAddress(cmd_args[0], 'proc *') if not pval: print "unknown arguments:", str(cmd_args) @@ -352,9 +764,7 @@ def ShowProcInfo(cmd_args=None): Usage: showprocinfo
""" if not cmd_args: - print "No arguments passed" - print ShowProcInfo.__doc__ - return False + raise ArgumentError("No arguments passed") pval = kern.GetValueFromAddress(cmd_args[0], 'proc *') if not pval: print "unknown arguments:", str(cmd_args) @@ -384,17 +794,6 @@ def ShowProcFiles(cmd_args=None): print "{0:-<5s} {0:-<18s} {0:-<10s} {0:-<8s} {0:-<18s} {0:-<64s}".format("") count = 0 - # Filetype map - filetype_dict = { - 1: 'VNODE', - 2: 'SOCKET', - 3: 'PSXSHM', - 4: 'PSXSEM', - 5: 'KQUEUE', - 6: 'PIPE', - 7: 'FSEVENTS' - } - while count <= proc_lastfile: if unsigned(proc_ofiles[count]) != 0: out_str = '' @@ -404,8 +803,8 @@ def ShowProcFiles(cmd_args=None): out_str += "{0: <#18x} ".format(unsigned(proc_fd_fglob)) out_str += "0x{0:0>8x} ".format(unsigned(proc_fd_flags)) proc_fd_ftype = unsigned(proc_fd_fglob.fg_ops.fo_type) - if proc_fd_ftype in filetype_dict: - out_str += "{0: <8s} ".format(filetype_dict[proc_fd_ftype]) + if proc_fd_ftype in xnudefines.filetype_strings: + out_str += "{0: <8s} ".format(xnudefines.filetype_strings[proc_fd_ftype]) else: out_str += "?: {0: <5d} ".format(proc_fd_ftype) out_str += "{0: <#18x} ".format(unsigned(proc_fd_fglob.fg_data)) @@ -488,6 +887,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 +961,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 +985,38 @@ 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('taskforpmap') +def TaskForPmap(cmd_args=None): + """ Find the task whose pmap corresponds to . + Syntax: (lldb) taskforpmap + Multiple -v's can be specified for increased verbosity + """ + if cmd_args == None or len(cmd_args) < 1: + raise ArgumentError("Too few arguments to taskforpmap.") + pmap = kern.GetValueFromAddress(cmd_args[0], 'pmap_t') + print GetTaskSummary.header + " " + GetProcSummary.header + for tasklist in [kern.tasks, kern.terminated_tasks]: + for t in tasklist: + if t.map.pmap == pmap: + pval = Cast(t.bsd_info, 'proc *') + out_str = GetTaskSummary(t) + " " + GetProcSummary(pval) + print out_str @lldb_command('showterminatedtasks') def ShowTerminatedTasks(cmd_args=None): @@ -604,6 +1096,52 @@ def ShowTaskStacksCmdHelper(cmd_args=None, cmd_options={}): # EndMacro: showtaskstacks +def CheckTaskProcRefs(task, proc): + for thread in IterateQueue(task.threads, 'thread *', 'task_threads'): + if int(thread.uthread) == 0: + continue + uthread = Cast(thread.uthread, 'uthread *') + refcount = int(uthread.uu_proc_refcount) + uu_ref_index = int(uthread.uu_pindex) + if refcount == 0: + continue + for ref in range(0, uu_ref_index): + if unsigned(uthread.uu_proc_ps[ref]) == unsigned(proc): + print GetTaskSummary.header + " " + GetProcSummary.header + pval = Cast(task.bsd_info, 'proc *') + print GetTaskSummary(task) + " " + GetProcSummary(pval) + print "\t" + GetThreadSummary.header + print "\t" + GetThreadSummary(thread) + "\n" + + for frame in range (0, 10): + trace_addr = unsigned(uthread.uu_proc_pcs[ref][frame]) + symbol_arr = kern.SymbolicateFromAddress(unsigned(trace_addr)) + if symbol_arr: + symbol_str = str(symbol_arr[0].addr) + else: + symbol_str = '' + print '{0: <#x} {1: + """ + if cmd_args == None or len(cmd_args) < 1: + raise ArgumentError("No arguments passed") + + proc = kern.GetValueFromAddress(cmd_args[0], 'proc *') + + for t in kern.tasks: + CheckTaskProcRefs(t, proc) + for t in kern.terminated_tasks: + CheckTaskProcRefs(t, proc) + + return + @lldb_command('showallthreads') def ShowAllThreads(cmd_args = None): """ Display info about all threads in the system @@ -611,6 +1149,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:") @@ -642,10 +1186,8 @@ def ShowAct(cmd_args=None): """ Routine to print out the state of a specific thread. usage: showact """ - if cmd_args == None or len(cmd_args) < 1: - print "No arguments passed" - print ShowAct.__doc__ - return False + if not cmd_args: + raise ArgumentError("No arguments passed") threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *') print GetThreadSummary.header print GetThreadSummary(threadval) @@ -655,10 +1197,8 @@ def ShowActStack(cmd_args=None): """ Routine to print out the stack of a specific thread. usage: showactstack """ - if cmd_args == None or len(cmd_args) < 1: - print "No arguments passed" - print ShowAct.__doc__.strip() - return False + if not cmd_args: + raise ArgumentError("No arguments passed") threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *') print GetThreadSummary.header print GetThreadSummary(threadval) @@ -674,10 +1214,8 @@ def SwitchToAct(cmd_args=None): Before resuming execution, issue a "resetctx" command, to return to the original execution context. """ - if cmd_args == None or len(cmd_args) < 1: - print "No arguments passed" - print SwitchToAct.__doc__.strip() - return False + if cmd_args is None or len(cmd_args) < 1: + raise ArgumentError("No arguments passed") thval = kern.GetValueFromAddress(cmd_args[0], 'thread *') lldbthread = GetLLDBThreadForKernelThread(thval) print GetThreadSummary.header @@ -686,6 +1224,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 +1263,8 @@ def ShowAllStacks(cmd_args=None): """ for t in kern.tasks: ShowTaskStacks(t) - print " \n" + print " \n" + ZombStacks() return # EndMacro: showallstacks @@ -706,7 +1277,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 +1298,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 +1323,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 (not kern.arch.startswith('arm') and frame_ptr < mh_execute_addr) or (kern.arch.startswith('arm') 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 +1341,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=[]): @@ -859,188 +1454,55 @@ def ShowThreadForTid(cmd_args=None): return print "Not a valid thread_id" -# Macro: showallprocessors - def GetProcessorSummary(processor): """ Internal function to print summary of 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) - return out_str + + 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]) -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) - runq_queue_i = 0 - runq_queue_count = sizeof(runq.queues)/sizeof(runq.queues[0]) - while runq.count and (runq_queue_i < 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 - return out_str + processor_recommended_str = "" + if int(processor.is_recommended) == 0: + processor_recommended_str = " (not recommended)" -def GetGrrrSummary(grrr_runq): - """ Internal function to print summary of grrr_run_queue - params: grrr_runq - value representing struct grrr_run_queue * - return: str - representing the details of given grrr_run_queue - """ - out_str = " GRRR Info: Count {: <10d} Weight {: <10d} Current Group {: <#012x}\n".format(grrr_runq.count, - 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): - 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 - return out_str + ast = 0 + preemption_disable = 0 + preemption_disable_str = "" -@lldb_command('showallprocessors') -def ShowAllProcessors(cmd_args=None): - """ Routine to print information of all psets and processors - Usage: showallprocessors - """ - pset = addressof(kern.globals.pset0) - 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 - - if sched_enum_val == 1: - show_priority_runq = 1 - show_fairshare_list = 1 - elif sched_enum_val == 2: - show_priority_pset_runq = 1 - show_fairshare_list = 1 - elif sched_enum_val == 4: - show_grrr = 1 - show_fairshare_grrr = 1 - elif sched_enum_val == 5: - show_priority_runq = 1 - show_fairshare_list = 1 - elif sched_enum_val == 6: - show_priority_pset_runq = 1 - show_fairshare_list = 1 + 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... - out_str = '' - while pset: - 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) - 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 *') - out_str += " " - out_str += GetProcessorSummary(processor) - if show_priority_runq: - runq = addressof(processor.runq) - out_str += GetRunQSummary(runq) - if show_grrr: - grrr_runq = addressof(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) - 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 += "\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) + ast_str = GetASTSummary(ast) - print out_str -# EndMacro: showallprocessors + if (preemption_disable != 0) : + preemption_disable_str = "Preemption Disabled" + + out_str = "Processor {: <#018x} cpu_id {:>#4x} AST: {:<6s} State {: unsigned(ledger.le_limit)): + if ((unsigned(ledger.le_credit) - unsigned(ledger.le_debit)) > unsigned(ledger.le_limit)): out_str += " X " else: out_str += " " @@ -1106,11 +1570,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} \ - {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")) -def GetTaskLedgers(task_val): +def GetTaskLedgers(task_val, show_footprint_interval_max=False): """ Internal function to get summary of ledger entries from the task and its threads params: task_val - value representing struct task * return: str - formatted output information for ledger entries of the input task @@ -1125,7 +1585,7 @@ def GetTaskLedgers(task_val): else: out_str += "Invalid process:\n" while i != task_ledgerp.l_template.lt_cnt: - out_str += GetLedgerEntrySummary(kern.globals.task_ledger_template, task_ledgerp.l_entries[i], i) + out_str += GetLedgerEntrySummary(kern.globals.task_ledger_template, task_ledgerp.l_entries[i], i, show_footprint_interval_max) i = i + 1 # Now walk threads @@ -1136,11 +1596,14 @@ def GetTaskLedgers(task_val): # Macro: showtaskledgers -@lldb_command('showtaskledgers', 'F:') +@lldb_command('showtaskledgers', 'F:I') def ShowTaskLedgers(cmd_args=None, cmd_options={}): """ Routine to print a summary of ledger entries for the task and all of its threads - Usage: showtaskledgers
- or : showtaskledgers -F + or : showtaskledgers [ -I ] [ -F ] + options: + -I: show footprint interval max (DEV/DEBUG only) + -F: specify task via name instead of address + - """ if "-F" in cmd_options: task_list = FindTasksByName(cmd_options["-F"]) @@ -1151,24 +1614,34 @@ def ShowTaskLedgers(cmd_args=None, cmd_options={}): if not cmd_args: raise ArgumentError("No arguments passed.") + show_footprint_interval_max = False + if "-I" in cmd_options: + show_footprint_interval_max = True tval = kern.GetValueFromAddress(cmd_args[0], 'task *') if not tval: raise ArgumentError("unknown arguments: %r" %cmd_args) - print GetTaskLedgers.header - print GetTaskLedgers(tval) + if (show_footprint_interval_max): + print "{0: <15s} {1: >16s} {2: <2s} {3: >15s} {4: >12s} {5: >14s} {6: >12s} {7: >12s} {8: >12s} {9: <15s} {10: <8s} {11: <9s} {12: <6s} {13: >6s}".format( + "task [thread]", "entry", "#", "balance", "intrvl_max", "lifetime_max", "credit", + "debit", "limit", "refill period", "lim pct", "warn pct", "over?", "flags") + else: + print "{0: <15s} {1: >16s} {2: <2s} {3: >15s} {4: >14s} {5: >12s} {6: >12s} {7: >12s} {8: <15s} {9: <8s} {10: <9s} {11: <6s} {12: >6s}".format( + "task [thread]", "entry", "#", "balance", "lifetime_max", "credit", + "debit", "limit", "refill period", "lim pct", "warn pct", "over?", "flags") + print GetTaskLedgers(tval, show_footprint_interval_max) # EndMacro: showtaskledgers # Macro: showalltaskledgers @lldb_command('showalltaskledgers') -def ShowAllTaskLedgers(cmd_args=None): +def ShowAllTaskLedgers(cmd_args=None, cmd_options={}): """ Routine to print a summary of ledger entries for all tasks and respective threads Usage: showalltaskledgers """ for t in kern.tasks: task_val = unsigned(t) - ShowTaskLedgers([task_val]) + ShowTaskLedgers([task_val], cmd_options=cmd_options) # EndMacro: showalltaskledgers @@ -1231,13 +1704,9 @@ def ShowAllTaskPolicy(cmd_args=None): ["bg_iotier", "bg-iotier"], ["terminated", "terminated"], ["th_pidbind_bg", "bg-pidbind"], - ["th_workq_bg", "bg-workq"], ["t_apptype", "apptype"], ["t_boosted", "boosted"], - ["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 +1727,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 +1754,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="" @@ -1295,26 +1764,322 @@ def ShowAllTaskPolicy(cmd_args=None): else: effective+="" - - pended_strings = [ - ["t_updating_policy", "updating"], - ["update_sockets", "update_sockets"], - ["t_update_timers", "update_timers"], - ["t_update_watchers", "update_watchers"] - ] - - pended="" - for value in pended_strings: - if t.pended_policy.__getattr__(value[0]) : - pended+=value[1] + ": " + str(t.pended_policy.__getattr__(value[0])) + " " - else: - pended+="" - print "requested: " + requested print "suppression: " + suppression print "effective: " + effective - 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 + +# Macro: showallpte +@lldb_command('showallpte') +def ShowAllPte(cmd_args=None): + """ Prints out the physical address of the pte for all tasks + """ + head_taskp = addressof(kern.globals.tasks) + taskp = Cast(head_taskp.next, 'task *') + while taskp != head_taskp: + procp = Cast(taskp.bsd_info, 'proc *') + out_str = "task = {:#x} pte = {:#x}\t".format(taskp, taskp.map.pmap.ttep) + if procp != 0: + out_str += "{:s}\n".format(procp.p_comm) + else: + out_str += "\n" + print out_str + taskp = Cast(taskp.tasks.next, 'struct task *') + +# EndMacro: showallpte + +# Macro: showallrefcounts +@lldb_command('showallrefcounts') +@header("{0: <20s} {1: ^10s}".format("task", "ref_count")) +def ShowAllRefCounts(cmd_args=None): + """ Prints the ref_count of all tasks + """ + out_str = '' + head_taskp = addressof(kern.globals.tasks) + taskp = Cast(head_taskp.next, 'task *') + print ShowAllRefCounts.header + while taskp != head_taskp: + out_str += "{: <#20x}".format(taskp) + out_str += "{: ^10d}\n".format(taskp.ref_count) + taskp = Cast(taskp.tasks.next, 'task *') + print out_str +# EndMacro: showallrefcounts + +# Macro: showallrunnablethreads +@lldb_command('showallrunnablethreads') +def ShowAllRunnableThreads(cmd_args=None): + """ Prints the sched usage information for all threads of each task + """ + out_str = '' + for taskp in kern.tasks: + for actp in IterateQueue(taskp.threads, 'thread *', 'task_threads'): + if int(actp.state & 0x4): + ShowActStack([unsigned(actp)]) + +# EndMacro: showallrunnablethreads + +# Macro: showallschedusage +@lldb_command('showallschedusage') +@header("{0:<20s} {1:^10s} {2:^10s} {3:^15s}".format("Thread", "Priority", "State", "sched_usage")) +def ShowAllSchedUsage(cmd_args=None): + """ Prints the sched usage information for all threads of each task + """ + out_str = '' + for taskp in kern.tasks: + ShowTask([unsigned(taskp)]) + print ShowAllSchedUsage.header + for actp in IterateQueue(taskp.threads, 'thread *', 'task_threads'): + out_str = "{: <#20x}".format(actp) + out_str += "{: ^10s}".format(str(int(actp.sched_pri))) + state = int(actp.state) + thread_state_chars = {0:'', 1:'W', 2:'S', 4:'R', 8:'U', 16:'H', 32:'A', 64:'P', 128:'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)] + out_str += "{: ^10s}".format(state_str) + out_str += "{: >15d}".format(actp.sched_usage) + print out_str + "\n" + print "\n\n" + +# EndMacro: showallschedusage + +#Macro: showprocfilessummary +@lldb_command('showprocfilessummary') +@header("{0: <20s} {1: <20s} {2: >10s}".format("Process", "Name", "Number of Open Files")) +def ShowProcFilesSummary(cmd_args=None): + """ Display the summary of open file descriptors for all processes in task list + Usage: showprocfilessummary + """ + print ShowProcFilesSummary.header + for proc in kern.procs: + proc_filedesc = proc.p_fd + proc_ofiles = proc_filedesc.fd_ofiles + proc_lastfile = unsigned(proc_filedesc.fd_lastfile) + count = 0 + proc_file_count = 0 + if proc_filedesc.fd_nfiles != 0: + while count <= proc_lastfile: + if unsigned(proc_ofiles[count]) != 0: + proc_file_count += 1 + count += 1 + print "{0: <#020x} {1: <20s} {2: >10d}".format(proc, proc.p_comm, proc_file_count) + +#EndMacro: showprocfilessummary + +@lldb_command('workinguserstacks') +def WorkingUserStacks(cmd_args=None): + """ Print out the user stack for each thread in a task, followed by the user libraries. + Syntax: (lldb) workinguserstacks + """ + if not cmd_args: + print "Insufficient arguments" + ShowTaskUserStacks.__doc__ + return False + task = kern.GetValueFromAddress(cmd_args[0], 'task *') + print GetTaskSummary.header + " " + GetProcSummary.header + pval = Cast(task.bsd_info, 'proc *') + print GetTaskSummary(task) + " " + GetProcSummary(pval) + "\n \n" + for thval in IterateQueue(task.threads, 'thread *', 'task_threads'): + print "For thread 0x{0:x}".format(thval) + try: + ShowThreadUserStack([hex(thval)]) + except Exception as exc_err: + print "Failed to show user stack for thread 0x{0:x}".format(thval) + if config['debug']: + raise exc_err + else: + print "Enable debugging ('(lldb) xnudebug debug') to see detailed trace." + WorkingUserLibraries([hex(task)]) + return + +@static_var("exec_load_path", 0) +@lldb_command("workingkuserlibraries") +def WorkingUserLibraries(cmd_args=None): + """ Show binary images known by dyld in target task + For a given user task, inspect the dyld shared library state and print information about all Mach-O images. + Syntax: (lldb)workinguserlibraries + """ + if not cmd_args: + print "Insufficient arguments" + print ShowTaskUserLibraries.__doc__ + return False + + print "{0: <18s} {1: <12s} {2: <36s} {3: <50s}".format('address','type','uuid','path') + out_format = "0x{0:0>16x} {1: <12s} {2: <36s} {3: <50s}" + task = kern.GetValueFromAddress(cmd_args[0], 'task_t') + is_task_64 = int(task.t_flags) & 0x1 + dyld_all_image_infos_address = unsigned(task.all_image_info_addr) + cur_data_offset = 0 + if dyld_all_image_infos_address == 0: + print "No dyld shared library information available for task" + return False + vers_info_data = GetUserDataAsString(task, dyld_all_image_infos_address, 112) + version = _ExtractDataFromString(vers_info_data, cur_data_offset, "uint32_t") + cur_data_offset += 4 + if version > 12: + print "Unknown dyld all_image_infos version number %d" % version + image_info_count = _ExtractDataFromString(vers_info_data, cur_data_offset, "uint32_t") + WorkingUserLibraries.exec_load_path = 0 + if is_task_64: + image_info_size = 24 + image_info_array_address = _ExtractDataFromString(vers_info_data, 8, "uint64_t") + dyld_load_address = _ExtractDataFromString(vers_info_data, 8*4, "uint64_t") + dyld_all_image_infos_address_from_struct = _ExtractDataFromString(vers_info_data, 8*13, "uint64_t") + else: + image_info_size = 12 + image_info_array_address = _ExtractDataFromString(vers_info_data, 4*2, "uint32_t") + dyld_load_address = _ExtractDataFromString(vers_info_data, 4*5, "uint32_t") + dyld_all_image_infos_address_from_struct = _ExtractDataFromString(vers_info_data, 4*14, "uint32_t") + # Account for ASLR slide before dyld can fix the structure + dyld_load_address = dyld_load_address + (dyld_all_image_infos_address - dyld_all_image_infos_address_from_struct) + + i = 0 + while i < image_info_count: + image_info_address = image_info_array_address + i * image_info_size + img_data = GetUserDataAsString(task, image_info_address, image_info_size) + if is_task_64: + image_info_addr = _ExtractDataFromString(img_data, 0, "uint64_t") + image_info_path = _ExtractDataFromString(img_data, 8, "uint64_t") + else: + image_info_addr = _ExtractDataFromString(img_data, 0, "uint32_t") + image_info_path = _ExtractDataFromString(img_data, 4, "uint32_t") + PrintImageInfo(task, image_info_addr, image_info_path) + i += 1 + + # load_path might get set when the main executable is processed. + if WorkingUserLibraries.exec_load_path != 0: + PrintImageInfo(task, dyld_load_address, WorkingUserLibraries.exec_load_path) + return + +# Macro: showstackaftertask +@lldb_command('showstackaftertask','F:') +def Showstackaftertask(cmd_args=None,cmd_options={}): + """ Routine to print the thread stacks for all tasks succeeding a given task + Usage: showstackaftertask <0xaddress of task> + or: showstackaftertask -F + """ + if "-F" in cmd_options: + # Find the task pointer corresponding to its task name + find_task_str = cmd_options["-F"] + task_list = FindTasksByName(find_task_str) + + # Iterate through the list of tasks and print all task stacks thereafter + for tval in task_list: + ListTaskStacks(tval) + return + + if not cmd_args: + raise ArgumentError("Insufficient arguments") + tval = kern.GetValueFromAddress(cmd_args[0], 'task *') + if not tval: + raise ArgumentError("unknown arguments: {:s}".format(str(cmd_args))) + else: + ListTaskStacks(tval) + + ZombStacks() + return +# EndMacro: showstackaftertask + +def ListTaskStacks(task): + """ Search for a given task and print the list of all task stacks thereafter. + """ + # Initialize local variable task_flag to mark when a given task is found. + task_flag=0 + + for t in kern.tasks: + if (task_flag == 1): + ShowTaskStacks(t) + print "\n" + if (t == task): + task_flag = 1 + +# Macro: showstackafterthread +@lldb_command('showstackafterthread') +def Showstackafterthread(cmd_args = None): + """ Routine to print the stacks of all threads succeeding a given thread. + Usage: Showstackafterthread <0xaddress of thread> + """ + # local variable thread_flag is used to mark when a given thread is found. + thread_flag=0 + if cmd_args: + threadval = kern.GetValueFromAddress(cmd_args[0], 'thread *') + else: + raise ArgumentError("No arguments passed") + # Iterate through list of all tasks to look up a given thread + for t in kern.tasks: + if(thread_flag==1): + pval = Cast(t.bsd_info, 'proc *') + print GetTaskSummary.header + " "+ GetProcSummary.header + print GetTaskSummary(t) + " "+ GetProcSummary(pval) + print "\n" + # Look up for a given thread from the the list of threads of a given task + for thval in IterateQueue(t.threads, 'thread *', 'task_threads'): + if (thread_flag==1): + print "\n" + print " " + GetThreadSummary.header + print " " + GetThreadSummary(thval) + print GetThreadBackTrace(thval, prefix="\t")+"\n" + print "\n" + + if(thval==threadval): + pval = Cast(t.bsd_info, 'proc *') + process_name = "{:s}".format(pval.p_comm) + print "\n\n" + print " *** Continuing to dump the thread stacks from the process *** :" + " " + process_name + print "\n\n" + thread_flag = 1 + print '\n' + return